Lazily allocate protocol-specific connection objects (#2190)
* Refactor Http[12]?Connection
This commit is contained in:
parent
b8a1c04ffb
commit
668f8e3b4b
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
private const int InnerLoopCount = 512;
|
||||
|
||||
public ReadableBuffer _buffer;
|
||||
public Http1Connection<object> _http1Connection;
|
||||
public Http1Connection _http1Connection;
|
||||
|
||||
[IterationSetup]
|
||||
public void Setup()
|
||||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
HttpParser = NullParser<Http1ParsingHandler>.Instance
|
||||
};
|
||||
|
||||
var http1Connection = new Http1Connection<object>(application: null, context: new Http1ConnectionContext
|
||||
var http1Connection = new Http1Connection(new Http1ConnectionContext
|
||||
{
|
||||
ServiceContext = serviceContext,
|
||||
ConnectionFeatures = new FeatureCollection(),
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
private static readonly Task _psuedoAsyncTask = Task.FromResult(27);
|
||||
private static readonly Func<object, Task> _psuedoAsyncTaskFunc = (obj) => _psuedoAsyncTask;
|
||||
|
||||
private readonly TestHttp1Connection<object> _http1Connection;
|
||||
private readonly TestHttp1Connection _http1Connection;
|
||||
private (IPipeConnection Transport, IPipeConnection Application) _pair;
|
||||
|
||||
private readonly byte[] _writeData;
|
||||
|
|
@ -92,7 +92,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
return _http1Connection.ResponseBody.WriteAsync(_writeData, 0, _writeData.Length, default(CancellationToken));
|
||||
}
|
||||
|
||||
private TestHttp1Connection<object> MakeHttp1Connection()
|
||||
private TestHttp1Connection MakeHttp1Connection()
|
||||
{
|
||||
using (var memoryPool = new MemoryPool())
|
||||
{
|
||||
|
|
@ -107,15 +107,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
HttpParser = new HttpParser<Http1ParsingHandler>()
|
||||
};
|
||||
|
||||
var http1Connection = new TestHttp1Connection<object>(
|
||||
application: null, context: new Http1ConnectionContext
|
||||
{
|
||||
ServiceContext = serviceContext,
|
||||
ConnectionFeatures = new FeatureCollection(),
|
||||
BufferPool = memoryPool,
|
||||
Application = pair.Application,
|
||||
Transport = pair.Transport
|
||||
});
|
||||
var http1Connection = new TestHttp1Connection(new Http1ConnectionContext
|
||||
{
|
||||
ServiceContext = serviceContext,
|
||||
ConnectionFeatures = new FeatureCollection(),
|
||||
BufferPool = memoryPool,
|
||||
Application = pair.Application,
|
||||
Transport = pair.Transport
|
||||
});
|
||||
|
||||
http1Connection.Reset();
|
||||
http1Connection.InitializeStreams(MessageBody.ZeroContentLengthKeepAlive);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
[ParameterizedJobConfig(typeof(CoreConfig))]
|
||||
public class HttpProtocolFeatureCollection
|
||||
{
|
||||
private readonly Http1Connection<object> _http1Connection;
|
||||
private readonly Http1Connection _http1Connection;
|
||||
private IFeatureCollection _collection;
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
|
|
@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
HttpParser = new HttpParser<Http1ParsingHandler>()
|
||||
};
|
||||
|
||||
var http1Connection = new Http1Connection<object>(application: null, context: new Http1ConnectionContext
|
||||
var http1Connection = new Http1Connection(new Http1ConnectionContext
|
||||
{
|
||||
ServiceContext = serviceContext,
|
||||
ConnectionFeatures = new FeatureCollection(),
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
{
|
||||
public IPipe Pipe { get; set; }
|
||||
|
||||
public Http1Connection<object> Http1Connection { get; set; }
|
||||
public Http1Connection Http1Connection { get; set; }
|
||||
|
||||
[IterationSetup]
|
||||
public void Setup()
|
||||
|
|
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
HttpParser = new HttpParser<Http1ParsingHandler>()
|
||||
};
|
||||
|
||||
var http1Connection = new Http1Connection<object>(application: null, context: new Http1ConnectionContext
|
||||
var http1Connection = new Http1Connection(new Http1ConnectionContext
|
||||
{
|
||||
ServiceContext = serviceContext,
|
||||
ConnectionFeatures = new FeatureCollection(),
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
HttpParser = new HttpParser<Http1ParsingHandler>()
|
||||
};
|
||||
|
||||
var http1Connection = new Http1Connection<object>(application: null, context: new Http1ConnectionContext
|
||||
var http1Connection = new Http1Connection(new Http1ConnectionContext
|
||||
{
|
||||
ServiceContext = serviceContext,
|
||||
ConnectionFeatures = new FeatureCollection(),
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
{
|
||||
private static readonly byte[] _helloWorldPayload = Encoding.ASCII.GetBytes("Hello, World!");
|
||||
|
||||
private TestHttp1Connection<object> _http1Connection;
|
||||
private TestHttp1Connection _http1Connection;
|
||||
|
||||
[Params(
|
||||
BenchmarkTypes.TechEmpowerPlaintext,
|
||||
|
|
@ -122,16 +122,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
HttpParser = new HttpParser<Http1ParsingHandler>()
|
||||
};
|
||||
|
||||
var http1Connection = new TestHttp1Connection<object>(
|
||||
application: null, context: new Http1ConnectionContext
|
||||
{
|
||||
ServiceContext = serviceContext,
|
||||
ConnectionFeatures = new FeatureCollection(),
|
||||
BufferPool = bufferPool,
|
||||
TimeoutControl = new MockTimeoutControl(),
|
||||
Application = pair.Application,
|
||||
Transport = pair.Transport
|
||||
});
|
||||
var http1Connection = new TestHttp1Connection(new Http1ConnectionContext
|
||||
{
|
||||
ServiceContext = serviceContext,
|
||||
ConnectionFeatures = new FeatureCollection(),
|
||||
BufferPool = bufferPool,
|
||||
TimeoutControl = new MockTimeoutControl(),
|
||||
Application = pair.Application,
|
||||
Transport = pair.Transport
|
||||
});
|
||||
|
||||
http1Connection.Reset();
|
||||
|
||||
|
|
|
|||
|
|
@ -6,13 +6,12 @@ using System.Diagnostics;
|
|||
using System.IO.Pipelines;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web.Utf8;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||
{
|
||||
public abstract partial class Http1Connection : HttpProtocol
|
||||
public partial class Http1Connection : HttpProtocol, IRequestProcessor
|
||||
{
|
||||
private const byte ByteAsterisk = (byte)'*';
|
||||
private const byte ByteForwardSlash = (byte)'/';
|
||||
|
|
@ -146,6 +145,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
{
|
||||
TimeoutControl.CancelTimeout();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -337,7 +337,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
QueryString = query.GetAsciiStringNonNullCharacters();
|
||||
}
|
||||
|
||||
private unsafe static string GetUtf8String(Span<byte> path)
|
||||
private static unsafe string GetUtf8String(Span<byte> path)
|
||||
{
|
||||
// .NET 451 doesn't have pointer overloads for Encoding.GetString so we
|
||||
// copy to an array
|
||||
|
|
@ -347,7 +347,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
}
|
||||
}
|
||||
|
||||
protected void EnsureHostHeaderExists()
|
||||
private void EnsureHostHeaderExists()
|
||||
{
|
||||
if (_httpVersion == Http.HttpVersion.Http10)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||
{
|
||||
public class Http1Connection<TContext> : Http1Connection
|
||||
{
|
||||
private readonly IHttpApplication<TContext> _application;
|
||||
|
||||
private TContext _httpContext;
|
||||
|
||||
public Http1Connection(IHttpApplication<TContext> application, Http1ConnectionContext context)
|
||||
: base(context)
|
||||
{
|
||||
_application = application;
|
||||
}
|
||||
|
||||
protected override void CreateHttpContext() => _httpContext = _application.CreateContext(this);
|
||||
|
||||
protected override void DisposeHttpContext() => _application.DisposeContext(_httpContext, _applicationException);
|
||||
|
||||
protected override Task InvokeApplicationAsync() => _application.ProcessRequestAsync(_httpContext);
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ using System.Runtime.CompilerServices;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Protocols;
|
||||
|
|
@ -391,12 +392,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
|
||||
protected abstract bool TryParseRequest(ReadResult result, out bool endConnection);
|
||||
|
||||
protected abstract void CreateHttpContext();
|
||||
|
||||
protected abstract void DisposeHttpContext();
|
||||
|
||||
protected abstract Task InvokeApplicationAsync();
|
||||
|
||||
private void CancelRequestAbortedToken()
|
||||
{
|
||||
try
|
||||
|
|
@ -440,7 +435,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
HttpRequestHeaders.Append(name, valueString);
|
||||
}
|
||||
|
||||
public async Task ProcessRequestsAsync()
|
||||
public async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> application)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -474,14 +469,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
|
||||
InitializeStreams(messageBody);
|
||||
|
||||
CreateHttpContext();
|
||||
var httpContext = application.CreateContext(this);
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
KestrelEventSource.Log.RequestStart(this);
|
||||
|
||||
await InvokeApplicationAsync();
|
||||
await application.ProcessRequestAsync(httpContext);
|
||||
|
||||
if (_requestAborted == 0)
|
||||
{
|
||||
|
|
@ -563,7 +559,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
}
|
||||
finally
|
||||
{
|
||||
DisposeHttpContext();
|
||||
application.DisposeContext(httpContext, _applicationException);
|
||||
|
||||
// StopStreams should be called before the end of the "if (!_requestProcessingStopping)" block
|
||||
// to ensure InitializeStreams has been called.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.Collections.Concurrent;
|
|||
using System.IO.Pipelines;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Protocols;
|
||||
|
|
@ -16,7 +17,7 @@ using Microsoft.Extensions.Logging;
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
public class Http2Connection : ITimeoutControl, IHttp2StreamLifetimeHandler, IHttpHeadersHandler
|
||||
public class Http2Connection : ITimeoutControl, IHttp2StreamLifetimeHandler, IHttpHeadersHandler, IRequestProcessor
|
||||
{
|
||||
private enum RequestHeaderParsingState
|
||||
{
|
||||
|
|
@ -93,13 +94,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
_frameWriter.Abort(ex);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
public void StopProcessingNextRequest()
|
||||
{
|
||||
_stopping = true;
|
||||
Input.CancelPendingRead();
|
||||
}
|
||||
|
||||
public async Task ProcessAsync<TContext>(IHttpApplication<TContext> application)
|
||||
public async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> application)
|
||||
{
|
||||
Exception error = null;
|
||||
var errorCode = Http2ErrorCode.NO_ERROR;
|
||||
|
|
@ -391,7 +392,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
else
|
||||
{
|
||||
// Start a new stream
|
||||
_currentHeadersStream = new Http2Stream<TContext>(application, new Http2StreamContext
|
||||
_currentHeadersStream = new Http2Stream(new Http2StreamContext
|
||||
{
|
||||
ConnectionId = ConnectionId,
|
||||
StreamId = _incomingFrame.StreamId,
|
||||
|
|
@ -412,7 +413,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
_currentHeadersStream.Reset();
|
||||
|
||||
var endHeaders = (_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_HEADERS) == Http2HeadersFrameFlags.END_HEADERS;
|
||||
await DecodeHeadersAsync(endHeaders, _incomingFrame.HeadersPayload);
|
||||
await DecodeHeadersAsync(application, endHeaders, _incomingFrame.HeadersPayload);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -541,7 +542,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdNotZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
|
||||
}
|
||||
|
||||
Stop();
|
||||
StopProcessingNextRequest();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
|
@ -602,7 +603,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
else
|
||||
{
|
||||
return DecodeHeadersAsync(endHeaders, _incomingFrame.Payload);
|
||||
return DecodeHeadersAsync(application, endHeaders, _incomingFrame.Payload);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -616,7 +617,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task DecodeHeadersAsync(bool endHeaders, Span<byte> payload)
|
||||
private Task DecodeHeadersAsync<TContext>(IHttpApplication<TContext> application, bool endHeaders, Span<byte> payload)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -624,7 +625,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
|
||||
if (endHeaders)
|
||||
{
|
||||
StartStream();
|
||||
StartStream(application);
|
||||
ResetRequestHeaderParsingState();
|
||||
}
|
||||
}
|
||||
|
|
@ -652,7 +653,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void StartStream()
|
||||
private void StartStream<TContext>(IHttpApplication<TContext> application)
|
||||
{
|
||||
if (!_isMethodConnect && (_parsedPseudoHeaderFields & _mandatoryRequestPseudoHeaderFields) != _mandatoryRequestPseudoHeaderFields)
|
||||
{
|
||||
|
|
@ -663,7 +664,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
|||
}
|
||||
|
||||
_streams[_incomingFrame.StreamId] = _currentHeadersStream;
|
||||
_ = _currentHeadersStream.ProcessRequestsAsync();
|
||||
_ = _currentHeadersStream.ProcessRequestsAsync(application);
|
||||
}
|
||||
|
||||
private void ResetRequestHeaderParsingState()
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
public abstract partial class Http2Stream : HttpProtocol
|
||||
public partial class Http2Stream : HttpProtocol
|
||||
{
|
||||
private readonly Http2StreamContext _context;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||
{
|
||||
public class Http2Stream<TContext> : Http2Stream
|
||||
{
|
||||
private readonly IHttpApplication<TContext> _application;
|
||||
|
||||
private TContext _httpContext;
|
||||
|
||||
public Http2Stream(IHttpApplication<TContext> application, Http2StreamContext context)
|
||||
: base(context)
|
||||
{
|
||||
_application = application;
|
||||
}
|
||||
|
||||
protected override void CreateHttpContext() => _httpContext = _application.CreateContext(this);
|
||||
|
||||
protected override void DisposeHttpContext() => _application.DisposeContext(_httpContext, _applicationException);
|
||||
|
||||
protected override Task InvokeApplicationAsync() => _application.ProcessRequestAsync(_httpContext);
|
||||
}
|
||||
}
|
||||
|
|
@ -21,30 +21,29 @@ using Microsoft.Extensions.Logging;
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||
{
|
||||
public class HttpConnection : ITimeoutControl, IConnectionTimeoutFeature
|
||||
public class HttpConnection : ITimeoutControl, IConnectionTimeoutFeature, IRequestProcessor
|
||||
{
|
||||
private const int Http2ConnectionNotStarted = 0;
|
||||
private const int Http2ConnectionStarted = 1;
|
||||
private const int Http2ConnectionClosed = 2;
|
||||
|
||||
private readonly HttpConnectionContext _context;
|
||||
private IList<IAdaptedConnection> _adaptedConnections;
|
||||
private readonly TaskCompletionSource<object> _socketClosedTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
private IList<IAdaptedConnection> _adaptedConnections;
|
||||
private IPipeConnection _adaptedTransport;
|
||||
|
||||
private readonly object _protocolSelectionLock = new object();
|
||||
private IRequestProcessor _requestProcessor;
|
||||
private Http1Connection _http1Connection;
|
||||
private Http2Connection _http2Connection;
|
||||
private volatile int _http2ConnectionState;
|
||||
|
||||
private long _lastTimestamp;
|
||||
private long _timeoutTimestamp = long.MaxValue;
|
||||
private TimeoutAction _timeoutAction;
|
||||
|
||||
private object _readTimingLock = new object();
|
||||
private readonly object _readTimingLock = new object();
|
||||
private bool _readTimingEnabled;
|
||||
private bool _readTimingPauseRequested;
|
||||
private long _readTimingElapsedTicks;
|
||||
private long _readTimingBytesRead;
|
||||
|
||||
private object _writeTimingLock = new object();
|
||||
private readonly object _writeTimingLock = new object();
|
||||
private int _writeTimingWrites;
|
||||
private long _writeTimingTimeoutTimestamp;
|
||||
|
||||
|
|
@ -53,6 +52,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
public HttpConnection(HttpConnectionContext context)
|
||||
{
|
||||
_context = context;
|
||||
_requestProcessor = this;
|
||||
}
|
||||
|
||||
// For testing
|
||||
|
|
@ -102,35 +102,29 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
|
||||
AdaptedPipeline adaptedPipeline = null;
|
||||
var adaptedPipelineTask = Task.CompletedTask;
|
||||
var transport = _context.Transport;
|
||||
|
||||
// _adaptedTransport must be set prior to adding the connection to the manager in order
|
||||
// to allow the connection to be aported prior to protocol selection.
|
||||
_adaptedTransport = _context.Transport;
|
||||
var application = _context.Application;
|
||||
|
||||
|
||||
if (_context.ConnectionAdapters.Count > 0)
|
||||
{
|
||||
adaptedPipeline = new AdaptedPipeline(transport,
|
||||
adaptedPipeline = new AdaptedPipeline(_adaptedTransport,
|
||||
application,
|
||||
new Pipe(AdaptedInputPipeOptions),
|
||||
new Pipe(AdaptedOutputPipeOptions));
|
||||
|
||||
transport = adaptedPipeline;
|
||||
_adaptedTransport = adaptedPipeline;
|
||||
}
|
||||
|
||||
// _http1Connection must be initialized before adding the connection to the connection manager
|
||||
CreateHttp1Connection(httpApplication, transport, application);
|
||||
|
||||
// _http2Connection must be initialized before yielding control to the transport thread,
|
||||
// to prevent a race condition where _http2Connection.Abort() is called just as
|
||||
// _http2Connection is about to be initialized.
|
||||
CreateHttp2Connection(httpApplication, transport, application);
|
||||
|
||||
// Do this before the first await so we don't yield control to the transport until we've
|
||||
// added the connection to the connection manager
|
||||
_context.ServiceContext.ConnectionManager.AddConnection(_context.HttpConnectionId, this);
|
||||
_lastTimestamp = _context.ServiceContext.SystemClock.UtcNow.Ticks;
|
||||
|
||||
_http1Connection.ConnectionFeatures.Set<IConnectionTimeoutFeature>(this);
|
||||
_http2Connection.ConnectionFeatures.Set<IConnectionTimeoutFeature>(this);
|
||||
_context.ConnectionFeatures.Set<IConnectionTimeoutFeature>(this);
|
||||
|
||||
if (adaptedPipeline != null)
|
||||
{
|
||||
|
|
@ -139,21 +133,41 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
adaptedPipelineTask = adaptedPipeline.RunAsync(stream);
|
||||
}
|
||||
|
||||
var protocol = SelectProtocol();
|
||||
IRequestProcessor requestProcessor = null;
|
||||
|
||||
if (protocol == HttpProtocols.None)
|
||||
lock (_protocolSelectionLock)
|
||||
{
|
||||
Abort(ex: null);
|
||||
// Ensure that the connection hasn't already been stopped.
|
||||
if (_requestProcessor == this)
|
||||
{
|
||||
switch (SelectProtocol())
|
||||
{
|
||||
case HttpProtocols.Http1:
|
||||
// _http1Connection must be initialized before adding the connection to the connection manager
|
||||
requestProcessor = _http1Connection = CreateHttp1Connection(_adaptedTransport, application);
|
||||
break;
|
||||
case HttpProtocols.Http2:
|
||||
// _http2Connection must be initialized before yielding control to the transport thread,
|
||||
// to prevent a race condition where _http2Connection.Abort() is called just as
|
||||
// _http2Connection is about to be initialized.
|
||||
requestProcessor = CreateHttp2Connection(_adaptedTransport, application);
|
||||
break;
|
||||
case HttpProtocols.None:
|
||||
// An error was already logged in SelectProtocol(), but we should close the connection.
|
||||
Abort(ex: null);
|
||||
break;
|
||||
default:
|
||||
// SelectProtocol() only returns Http1, Http2 or None.
|
||||
throw new NotSupportedException($"{nameof(SelectProtocol)} returned something other than Http1, Http2 or None.");
|
||||
}
|
||||
|
||||
_requestProcessor = requestProcessor;
|
||||
}
|
||||
}
|
||||
|
||||
// One of these has to run even if no protocol was selected so the abort propagates and everything completes properly
|
||||
if (protocol == HttpProtocols.Http2 && Interlocked.CompareExchange(ref _http2ConnectionState, Http2ConnectionStarted, Http2ConnectionNotStarted) == Http2ConnectionNotStarted)
|
||||
if (requestProcessor != null)
|
||||
{
|
||||
await _http2Connection.ProcessAsync(httpApplication);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _http1Connection.ProcessRequestsAsync();
|
||||
await requestProcessor.ProcessRequestsAsync(httpApplication);
|
||||
}
|
||||
|
||||
await adaptedPipelineTask;
|
||||
|
|
@ -161,14 +175,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.LogError(0, ex, $"Unexpected exception in {nameof(HttpConnection)}.{nameof(ProcessRequestsAsync)}.");
|
||||
Log.LogCritical(0, ex, $"Unexpected exception in {nameof(HttpConnection)}.{nameof(ProcessRequestsAsync)}.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
_context.ServiceContext.ConnectionManager.RemoveConnection(_context.HttpConnectionId);
|
||||
DisposeAdaptedConnections();
|
||||
|
||||
if (_http1Connection.IsUpgraded)
|
||||
if (_http1Connection?.IsUpgraded == true)
|
||||
{
|
||||
_context.ServiceContext.ConnectionManager.UpgradedConnectionCount.ReleaseOne();
|
||||
}
|
||||
|
|
@ -177,9 +191,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
}
|
||||
}
|
||||
|
||||
internal void CreateHttp1Connection<TContext>(IHttpApplication<TContext> httpApplication, IPipeConnection transport, IPipeConnection application)
|
||||
// For testing only
|
||||
internal void Initialize(IPipeConnection transport, IPipeConnection application)
|
||||
{
|
||||
_http1Connection = new Http1Connection<TContext>(httpApplication, new Http1ConnectionContext
|
||||
_requestProcessor = _http1Connection = CreateHttp1Connection(transport, application);
|
||||
}
|
||||
|
||||
private Http1Connection CreateHttp1Connection(IPipeConnection transport, IPipeConnection application)
|
||||
{
|
||||
return new Http1Connection(new Http1ConnectionContext
|
||||
{
|
||||
ConnectionId = _context.ConnectionId,
|
||||
ConnectionFeatures = _context.ConnectionFeatures,
|
||||
|
|
@ -193,9 +213,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
});
|
||||
}
|
||||
|
||||
internal void CreateHttp2Connection<TContext>(IHttpApplication<TContext> httpApplication, IPipeConnection transport, IPipeConnection application)
|
||||
private Http2Connection CreateHttp2Connection(IPipeConnection transport, IPipeConnection application)
|
||||
{
|
||||
_http2Connection = new Http2Connection(new Http2ConnectionContext
|
||||
return new Http2Connection(new Http2ConnectionContext
|
||||
{
|
||||
ConnectionId = _context.ConnectionId,
|
||||
ServiceContext = _context.ServiceContext,
|
||||
|
|
@ -217,16 +237,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
|
||||
public Task StopProcessingNextRequestAsync()
|
||||
{
|
||||
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
||||
Debug.Assert(_http2Connection != null, $"{nameof(_http2Connection)} is null");
|
||||
|
||||
if (Interlocked.Exchange(ref _http2ConnectionState, Http2ConnectionClosed) == Http2ConnectionStarted)
|
||||
lock (_protocolSelectionLock)
|
||||
{
|
||||
_http2Connection.Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
_http1Connection.StopProcessingNextRequest();
|
||||
_requestProcessor?.StopProcessingNextRequest();
|
||||
_requestProcessor = null;
|
||||
}
|
||||
|
||||
return _lifetimeTask;
|
||||
|
|
@ -234,17 +248,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
|
||||
public void Abort(Exception ex)
|
||||
{
|
||||
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
||||
Debug.Assert(_http2Connection != null, $"{nameof(_http2Connection)} is null");
|
||||
|
||||
// Abort the connection (if not already aborted)
|
||||
if (Interlocked.Exchange(ref _http2ConnectionState, Http2ConnectionClosed) == Http2ConnectionStarted)
|
||||
lock (_protocolSelectionLock)
|
||||
{
|
||||
_http2Connection.Abort(ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
_http1Connection.Abort(ex);
|
||||
_requestProcessor?.Abort(ex);
|
||||
_requestProcessor = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -255,28 +262,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
return _lifetimeTask;
|
||||
}
|
||||
|
||||
public void SendTimeoutResponse()
|
||||
{
|
||||
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
||||
Debug.Assert(_http2Connection != null, $"{nameof(_http2Connection)} is null");
|
||||
|
||||
RequestTimedOut = true;
|
||||
_http1Connection.SendTimeoutResponse();
|
||||
}
|
||||
|
||||
public void StopProcessingNextRequest()
|
||||
{
|
||||
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
||||
Debug.Assert(_http2Connection != null, $"{nameof(_http2Connection)} is null");
|
||||
|
||||
_http1Connection.StopProcessingNextRequest();
|
||||
}
|
||||
|
||||
private async Task<Stream> ApplyConnectionAdaptersAsync()
|
||||
{
|
||||
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
||||
Debug.Assert(_http2Connection != null, $"{nameof(_http2Connection)} is null");
|
||||
|
||||
var connectionAdapters = _context.ConnectionAdapters;
|
||||
var stream = new RawStream(_context.Transport.Input, _context.Transport.Output);
|
||||
var adapterContext = new ConnectionAdapterContext(_context.ConnectionFeatures, stream);
|
||||
|
|
@ -348,14 +335,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
|
||||
public void Tick(DateTimeOffset now)
|
||||
{
|
||||
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
||||
Debug.Assert(_http2Connection != null, $"{nameof(_http2Connection)} is null");
|
||||
|
||||
var timestamp = now.Ticks;
|
||||
|
||||
CheckForTimeout(timestamp);
|
||||
CheckForReadDataRateTimeout(timestamp);
|
||||
CheckForWriteDataRateTimeout(timestamp);
|
||||
|
||||
// HTTP/2 rate timeouts are not yet supported.
|
||||
if (_http1Connection != null)
|
||||
{
|
||||
CheckForReadDataRateTimeout(timestamp);
|
||||
CheckForWriteDataRateTimeout(timestamp);
|
||||
}
|
||||
|
||||
Interlocked.Exchange(ref _lastTimestamp, timestamp);
|
||||
}
|
||||
|
|
@ -372,12 +361,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
switch (_timeoutAction)
|
||||
{
|
||||
case TimeoutAction.StopProcessingNextRequest:
|
||||
StopProcessingNextRequest();
|
||||
// Http/2 keep-alive timeouts are not yet supported.
|
||||
_http1Connection?.StopProcessingNextRequest();
|
||||
break;
|
||||
case TimeoutAction.SendTimeoutResponse:
|
||||
SendTimeoutResponse();
|
||||
// HTTP/2 timeout responses are not yet supported.
|
||||
if (_http1Connection != null)
|
||||
{
|
||||
RequestTimedOut = true;
|
||||
_http1Connection.SendTimeoutResponse();
|
||||
}
|
||||
break;
|
||||
case TimeoutAction.AbortConnection:
|
||||
// This is actually supported with HTTP/2!
|
||||
Abort(new TimeoutException());
|
||||
break;
|
||||
}
|
||||
|
|
@ -387,6 +383,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
|
||||
private void CheckForReadDataRateTimeout(long timestamp)
|
||||
{
|
||||
Debug.Assert(_http1Connection != null);
|
||||
|
||||
// The only time when both a timeout is set and the read data rate could be enforced is
|
||||
// when draining the request body. Since there's already a (short) timeout set for draining,
|
||||
// it's safe to not check the data rate at this point.
|
||||
|
|
@ -412,7 +410,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
if (rate < minRequestBodyDataRate.BytesPerSecond && !Debugger.IsAttached)
|
||||
{
|
||||
Log.RequestBodyMininumDataRateNotSatisfied(_context.ConnectionId, _http1Connection.TraceIdentifier, minRequestBodyDataRate.BytesPerSecond);
|
||||
SendTimeoutResponse();
|
||||
RequestTimedOut = true;
|
||||
_http1Connection.SendTimeoutResponse();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -430,6 +429,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
|
||||
private void CheckForWriteDataRateTimeout(long timestamp)
|
||||
{
|
||||
Debug.Assert(_http1Connection != null);
|
||||
|
||||
lock (_writeTimingLock)
|
||||
{
|
||||
if (_writeTimingWrites > 0 && timestamp > _writeTimingTimeoutTimestamp && !Debugger.IsAttached)
|
||||
|
|
@ -510,6 +511,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
|
||||
public void StartTimingWrite(long size)
|
||||
{
|
||||
Debug.Assert(_http1Connection != null);
|
||||
|
||||
lock (_writeTimingLock)
|
||||
{
|
||||
var minResponseDataRate = _http1Connection.MinResponseDataRate;
|
||||
|
|
@ -563,5 +566,33 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
|||
|
||||
ResetTimeout(timeSpan.Ticks, TimeoutAction.AbortConnection);
|
||||
}
|
||||
|
||||
private void CloseUninitializedConnection()
|
||||
{
|
||||
Debug.Assert(_adaptedTransport != null);
|
||||
|
||||
// CancelPendingRead signals the transport directly to close the connection
|
||||
// without any potential interference from connection adapters.
|
||||
_context.Application.Input.CancelPendingRead();
|
||||
|
||||
_adaptedTransport.Input.Complete();
|
||||
_adaptedTransport.Output.Complete();
|
||||
}
|
||||
|
||||
// These IStoppableConnection methods only get called if the server shuts down during initialization.
|
||||
Task IRequestProcessor.ProcessRequestsAsync<TContext>(IHttpApplication<TContext> application)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
void IRequestProcessor.StopProcessingNextRequest()
|
||||
{
|
||||
CloseUninitializedConnection();
|
||||
}
|
||||
|
||||
void IRequestProcessor.Abort(Exception ex)
|
||||
{
|
||||
CloseUninitializedConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||
{
|
||||
public interface IRequestProcessor
|
||||
{
|
||||
Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> application);
|
||||
void StopProcessingNextRequest();
|
||||
void Abort(Exception ex);
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
||||
|
|
@ -30,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
{
|
||||
private readonly IPipeConnection _transport;
|
||||
private readonly IPipeConnection _application;
|
||||
private readonly TestHttp1Connection<object> _http1Connection;
|
||||
private readonly TestHttp1Connection _http1Connection;
|
||||
private readonly ServiceContext _serviceContext;
|
||||
private readonly Http1ConnectionContext _http1ConnectionContext;
|
||||
private readonly BufferPool _pipelineFactory;
|
||||
|
|
@ -38,19 +37,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
private ReadCursor _examined;
|
||||
private Mock<ITimeoutControl> _timeoutControl;
|
||||
|
||||
private class TestHttp1Connection<TContext> : Http1Connection<TContext>
|
||||
{
|
||||
public TestHttp1Connection(IHttpApplication<TContext> application, Http1ConnectionContext context)
|
||||
: base(application, context)
|
||||
{
|
||||
}
|
||||
|
||||
public Task ProduceEndAsync()
|
||||
{
|
||||
return ProduceEnd();
|
||||
}
|
||||
}
|
||||
|
||||
public Http1ConnectionTests()
|
||||
{
|
||||
_pipelineFactory = new MemoryPool();
|
||||
|
|
@ -71,7 +57,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
Transport = pair.Transport
|
||||
};
|
||||
|
||||
_http1Connection = new TestHttp1Connection<object>(application: null, context: _http1ConnectionContext);
|
||||
_http1Connection = new TestHttp1Connection(_http1ConnectionContext);
|
||||
_http1Connection.Reset();
|
||||
}
|
||||
|
||||
|
|
@ -509,7 +495,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
[Fact]
|
||||
public void ProcessRequestsAsyncEnablesKeepAliveTimeout()
|
||||
{
|
||||
var requestProcessingTask = _http1Connection.ProcessRequestsAsync();
|
||||
var requestProcessingTask = _http1Connection.ProcessRequestsAsync<object>(null);
|
||||
|
||||
var expectedKeepAliveTimeout = _serviceContext.ServerOptions.Limits.KeepAliveTimeout.Ticks;
|
||||
_timeoutControl.Verify(cc => cc.SetTimeout(expectedKeepAliveTimeout, TimeoutAction.StopProcessingNextRequest));
|
||||
|
|
@ -594,7 +580,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
[Fact]
|
||||
public async Task RequestProcessingTaskIsUnwrapped()
|
||||
{
|
||||
var requestProcessingTask = _http1Connection.ProcessRequestsAsync();
|
||||
var requestProcessingTask = _http1Connection.ProcessRequestsAsync<object>(null);
|
||||
|
||||
var data = Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\nHost:\r\n\r\n");
|
||||
await _application.Output.WriteAsync(data);
|
||||
|
|
@ -723,7 +709,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var headers0 = MakeHeaders(header0Count);
|
||||
var headers1 = MakeHeaders(header1Count, header0Count);
|
||||
|
||||
var requestProcessingTask = _http1Connection.ProcessRequestsAsync();
|
||||
var requestProcessingTask = _http1Connection.ProcessRequestsAsync<object>(null);
|
||||
|
||||
await _application.Output.WriteAsync(Encoding.ASCII.GetBytes("GET / HTTP/1.0\r\n"));
|
||||
await WaitForCondition(TimeSpan.FromSeconds(1), () => _http1Connection.RequestHeaders != null);
|
||||
|
|
@ -757,7 +743,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var headers0 = MakeHeaders(header0Count);
|
||||
var headers1 = MakeHeaders(header1Count, header0Count);
|
||||
|
||||
var requestProcessingTask = _http1Connection.ProcessRequestsAsync();
|
||||
var requestProcessingTask = _http1Connection.ProcessRequestsAsync<object>(null);
|
||||
|
||||
await _application.Output.WriteAsync(Encoding.ASCII.GetBytes("GET / HTTP/1.0\r\n"));
|
||||
await WaitForCondition(TimeSpan.FromSeconds(1), () => _http1Connection.RequestHeaders != null);
|
||||
|
|
|
|||
|
|
@ -1987,7 +1987,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
private async Task InitializeConnectionAsync(RequestDelegate application)
|
||||
{
|
||||
_connectionTask = _connection.ProcessAsync(new DummyApplication(application));
|
||||
_connectionTask = _connection.ProcessRequestsAsync(new DummyApplication(application));
|
||||
|
||||
await SendPreambleAsync().ConfigureAwait(false);
|
||||
await SendSettingsAsync();
|
||||
|
|
|
|||
|
|
@ -56,8 +56,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var mockDebugger = new Mock<IDebugger>();
|
||||
mockDebugger.SetupGet(g => g.IsAttached).Returns(true);
|
||||
_httpConnection.Debugger = mockDebugger.Object;
|
||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Initialize(_httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
|
||||
var now = DateTimeOffset.Now;
|
||||
_httpConnection.Tick(now);
|
||||
|
|
@ -104,8 +103,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
|
||||
_httpConnectionContext.ServiceContext.Log = logger;
|
||||
|
||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Initialize(_httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Http1Connection.Reset();
|
||||
|
||||
// Initialize timestamp
|
||||
|
|
@ -132,8 +130,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var mockLogger = new Mock<IKestrelTrace>();
|
||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||
|
||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Initialize(_httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Http1Connection.Reset();
|
||||
|
||||
// Initialize timestamp
|
||||
|
|
@ -175,8 +172,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var mockLogger = new Mock<IKestrelTrace>();
|
||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||
|
||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Initialize(_httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Http1Connection.Reset();
|
||||
|
||||
// Initialize timestamp
|
||||
|
|
@ -253,8 +249,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var mockLogger = new Mock<IKestrelTrace>();
|
||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||
|
||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Initialize(_httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Http1Connection.Reset();
|
||||
|
||||
// Initialize timestamp
|
||||
|
|
@ -322,8 +317,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var mockLogger = new Mock<IKestrelTrace>();
|
||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||
|
||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Initialize(_httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Http1Connection.Reset();
|
||||
|
||||
// Initialize timestamp
|
||||
|
|
@ -385,8 +379,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var mockLogger = new Mock<IKestrelTrace>();
|
||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||
|
||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Initialize(_httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Http1Connection.Reset();
|
||||
|
||||
var startTime = systemClock.UtcNow;
|
||||
|
|
@ -427,8 +420,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var mockLogger = new Mock<IKestrelTrace>();
|
||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||
|
||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Initialize(_httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Http1Connection.Reset();
|
||||
_httpConnection.Http1Connection.RequestAborted.Register(() =>
|
||||
{
|
||||
|
|
@ -462,8 +454,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var mockLogger = new Mock<IKestrelTrace>();
|
||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||
|
||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Initialize(_httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Http1Connection.Reset();
|
||||
_httpConnection.Http1Connection.RequestAborted.Register(() =>
|
||||
{
|
||||
|
|
@ -505,8 +496,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
var mockLogger = new Mock<IKestrelTrace>();
|
||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||
|
||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Initialize(_httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||
_httpConnection.Http1Connection.Reset();
|
||||
_httpConnection.Http1Connection.RequestAborted.Register(() =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
TimeoutControl = null
|
||||
};
|
||||
|
||||
var http1Connection = new Http1Connection<object>(application: null, context: http1ConnectionContext);
|
||||
var http1Connection = new Http1Connection(http1ConnectionContext);
|
||||
|
||||
http1Connection.Reset();
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
TimeoutControl = Mock.Of<ITimeoutControl>()
|
||||
};
|
||||
|
||||
Http1Connection = new Http1Connection<object>(null, Http1ConnectionContext);
|
||||
Http1Connection = new Http1Connection(Http1ConnectionContext);
|
||||
Http1Connection.HttpResponseControl = Mock.Of<IHttpResponseControl>();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -708,7 +708,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
|||
var socket = new MockSocket(_mockLibuv, _libuvThread.Loop.ThreadId, transportContext.Log);
|
||||
var consumer = new LibuvOutputConsumer(pair.Application.Input, _libuvThread, socket, "0", transportContext.Log);
|
||||
|
||||
var http1Connection = new Http1Connection<object>(null, new Http1ConnectionContext
|
||||
var http1Connection = new Http1Connection(new Http1ConnectionContext
|
||||
{
|
||||
ServiceContext = serviceContext,
|
||||
ConnectionFeatures = new FeatureCollection(),
|
||||
|
|
|
|||
|
|
@ -2,16 +2,14 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||
|
||||
namespace Microsoft.AspNetCore.Testing
|
||||
{
|
||||
public class TestHttp1Connection<TContext> : Http1Connection<TContext>
|
||||
public class TestHttp1Connection : Http1Connection
|
||||
{
|
||||
public TestHttp1Connection(IHttpApplication<TContext> application, Http1ConnectionContext context)
|
||||
: base(application, context)
|
||||
public TestHttp1Connection(Http1ConnectionContext context)
|
||||
: base(context)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue