Reuse headers to prevent values moving to higher GC gens
This commit is contained in:
parent
dfcd6a6227
commit
c293bbbd1a
|
|
@ -34,8 +34,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
private static readonly byte[] _bytesHttpVersion1_1 = Encoding.ASCII.GetBytes("HTTP/1.1 ");
|
||||
private static readonly byte[] _bytesContentLengthZero = Encoding.ASCII.GetBytes("\r\nContent-Length: 0");
|
||||
private static readonly byte[] _bytesSpace = Encoding.ASCII.GetBytes(" ");
|
||||
private static readonly byte[] _bytesServer = Encoding.ASCII.GetBytes("\r\nServer: Kestrel");
|
||||
private static readonly byte[] _bytesDate = Encoding.ASCII.GetBytes("Date: ");
|
||||
private static readonly byte[] _bytesEndHeaders = Encoding.ASCII.GetBytes("\r\n\r\n");
|
||||
|
||||
private static Vector<byte> _vectorCRs = new Vector<byte>((byte)'\r');
|
||||
|
|
@ -46,8 +44,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
|
||||
private readonly object _onStartingSync = new Object();
|
||||
private readonly object _onCompletedSync = new Object();
|
||||
protected readonly FrameRequestHeaders _requestHeaders = new FrameRequestHeaders();
|
||||
private readonly FrameResponseHeaders _responseHeaders = new FrameResponseHeaders();
|
||||
|
||||
private Headers _frameHeaders;
|
||||
private Streams _frameStreams;
|
||||
|
||||
protected List<KeyValuePair<Func<object, Task>, object>> _onStarting;
|
||||
|
||||
|
|
@ -60,10 +59,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
protected CancellationTokenSource _abortedCts;
|
||||
protected CancellationToken? _manuallySetRequestAbortToken;
|
||||
|
||||
internal FrameRequestStream _requestBody;
|
||||
internal FrameResponseStream _responseBody;
|
||||
internal FrameDuplexStream _duplexStream;
|
||||
|
||||
protected bool _responseStarted;
|
||||
protected bool _keepAlive;
|
||||
private bool _autoChunk;
|
||||
|
|
@ -92,12 +87,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
_localEndPoint = localEndPoint;
|
||||
_prepareRequest = prepareRequest;
|
||||
_pathBase = context.ServerAddress.PathBase;
|
||||
if (ReuseStreams)
|
||||
{
|
||||
_requestBody = new FrameRequestStream();
|
||||
_responseBody = new FrameResponseStream(this);
|
||||
_duplexStream = new FrameDuplexStream(_requestBody, _responseBody);
|
||||
}
|
||||
|
||||
FrameControl = this;
|
||||
Reset();
|
||||
|
|
@ -197,8 +186,48 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
get { return _responseStarted; }
|
||||
}
|
||||
|
||||
protected FrameRequestHeaders FrameRequestHeaders => _frameHeaders.RequestHeaders;
|
||||
|
||||
public Frame InitializeHeaders()
|
||||
{
|
||||
_frameHeaders = HttpComponentFactory.CreateHeaders(DateHeaderValueManager);
|
||||
RequestHeaders = _frameHeaders.RequestHeaders;
|
||||
ResponseHeaders = _frameHeaders.ResponseHeaders;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public void InitializeStreams(MessageBody messageBody)
|
||||
{
|
||||
_frameStreams = HttpComponentFactory.CreateStreams(this);
|
||||
|
||||
RequestBody = _frameStreams.RequestBody.StartAcceptingReads(messageBody);
|
||||
ResponseBody = _frameStreams.ResponseBody.StartAcceptingWrites();
|
||||
DuplexStream = _frameStreams.DuplexStream;
|
||||
}
|
||||
|
||||
public void PauseStreams()
|
||||
{
|
||||
_frameStreams.RequestBody.PauseAcceptingReads();
|
||||
_frameStreams.ResponseBody.PauseAcceptingWrites();
|
||||
}
|
||||
|
||||
public void ResumeStreams()
|
||||
{
|
||||
_frameStreams.RequestBody.ResumeAcceptingReads();
|
||||
_frameStreams.ResponseBody.ResumeAcceptingWrites();
|
||||
}
|
||||
|
||||
public void StopStreams()
|
||||
{
|
||||
_frameStreams.RequestBody.StopAcceptingReads();
|
||||
_frameStreams.ResponseBody.StopAcceptingWrites();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
ResetComponents(poolingPermitted: true);
|
||||
|
||||
_onStarting = null;
|
||||
_onCompleted = null;
|
||||
|
||||
|
|
@ -207,8 +236,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
_autoChunk = false;
|
||||
_applicationException = null;
|
||||
|
||||
_requestHeaders.Reset();
|
||||
ResetResponseHeaders();
|
||||
ResetFeatureCollection();
|
||||
|
||||
Scheme = null;
|
||||
|
|
@ -218,13 +245,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
Path = null;
|
||||
QueryString = null;
|
||||
_httpVersion = HttpVersionType.Unknown;
|
||||
RequestHeaders = _requestHeaders;
|
||||
RequestBody = null;
|
||||
StatusCode = 200;
|
||||
ReasonPhrase = null;
|
||||
ResponseHeaders = _responseHeaders;
|
||||
ResponseBody = null;
|
||||
DuplexStream = null;
|
||||
|
||||
var httpConnectionFeature = this as IHttpConnectionFeature;
|
||||
httpConnectionFeature.RemoteIpAddress = _remoteEndPoint?.Address;
|
||||
|
|
@ -239,15 +261,26 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
_abortedCts = null;
|
||||
}
|
||||
|
||||
public void ResetResponseHeaders()
|
||||
protected void ResetComponents(bool poolingPermitted)
|
||||
{
|
||||
_responseHeaders.Reset();
|
||||
_responseHeaders.SetRawDate(
|
||||
DateHeaderValueManager.GetDateHeaderValue(),
|
||||
DateHeaderValueManager.GetDateHeaderValueBytes());
|
||||
_responseHeaders.SetRawServer(
|
||||
"Kestrel",
|
||||
_bytesServer);
|
||||
if (_frameHeaders != null)
|
||||
{
|
||||
RequestHeaders = null;
|
||||
ResponseHeaders = null;
|
||||
var frameHeaders = _frameHeaders;
|
||||
_frameHeaders = null;
|
||||
HttpComponentFactory.DisposeHeaders(frameHeaders, poolingPermitted);
|
||||
}
|
||||
|
||||
if (_frameStreams != null)
|
||||
{
|
||||
RequestBody = null;
|
||||
ResponseBody = null;
|
||||
DuplexStream = null;
|
||||
var frameStreams = _frameStreams;
|
||||
_frameStreams = null;
|
||||
HttpComponentFactory.DisposeStreams(frameStreams, poolingPermitted: (poolingPermitted && ReuseStreams));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -292,8 +325,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
{
|
||||
_requestProcessingStopping = true;
|
||||
|
||||
_requestBody?.Abort();
|
||||
_responseBody?.Abort();
|
||||
_frameStreams?.RequestBody.Abort();
|
||||
_frameStreams?.ResponseBody.Abort();
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -560,8 +593,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
StatusCode = 500;
|
||||
ReasonPhrase = null;
|
||||
|
||||
ResetResponseHeaders();
|
||||
_responseHeaders.SetRawContentLength("0", _bytesContentLengthZero);
|
||||
var responseHeaders = _frameHeaders.ResponseHeaders;
|
||||
responseHeaders.Reset();
|
||||
responseHeaders.SetRawDate(
|
||||
DateHeaderValueManager.GetDateHeaderValue(),
|
||||
DateHeaderValueManager.GetDateHeaderValueBytes());
|
||||
responseHeaders.SetRawServer(
|
||||
"Kestrel",
|
||||
Headers.BytesServer);
|
||||
responseHeaders.SetRawContentLength("0", _bytesContentLengthZero);
|
||||
|
||||
ResponseHeaders = responseHeaders;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -615,9 +657,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
bool appCompleted)
|
||||
{
|
||||
var end = SocketOutput.ProducingStart();
|
||||
var responseHeaders = _frameHeaders.ResponseHeaders;
|
||||
if (_keepAlive)
|
||||
{
|
||||
foreach (var connectionValue in _responseHeaders.HeaderConnection)
|
||||
foreach (var connectionValue in responseHeaders.HeaderConnection)
|
||||
{
|
||||
if (connectionValue.IndexOf("close", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
|
|
@ -626,7 +669,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
}
|
||||
}
|
||||
|
||||
if (_keepAlive && !_responseHeaders.HasTransferEncoding && !_responseHeaders.HasContentLength)
|
||||
if (_keepAlive && !responseHeaders.HasTransferEncoding && !responseHeaders.HasContentLength)
|
||||
{
|
||||
if (appCompleted)
|
||||
{
|
||||
|
|
@ -636,7 +679,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
{
|
||||
// Since the app has completed and we are only now generating
|
||||
// the headers we can safely set the Content-Length to 0.
|
||||
_responseHeaders.SetRawContentLength("0", _bytesContentLengthZero);
|
||||
responseHeaders.SetRawContentLength("0", _bytesContentLengthZero);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -644,7 +687,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
if (_httpVersion == HttpVersionType.Http1_1)
|
||||
{
|
||||
_autoChunk = true;
|
||||
_responseHeaders.SetRawTransferEncoding("chunked", _bytesTransferEncodingChunked);
|
||||
responseHeaders.SetRawTransferEncoding("chunked", _bytesTransferEncodingChunked);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -653,18 +696,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
}
|
||||
}
|
||||
|
||||
if (_keepAlive == false && _responseHeaders.HasConnection == false && _httpVersion == HttpVersionType.Http1_1)
|
||||
if (_keepAlive == false && responseHeaders.HasConnection == false && _httpVersion == HttpVersionType.Http1_1)
|
||||
{
|
||||
_responseHeaders.SetRawConnection("close", _bytesConnectionClose);
|
||||
responseHeaders.SetRawConnection("close", _bytesConnectionClose);
|
||||
}
|
||||
else if (_keepAlive && _responseHeaders.HasConnection == false && _httpVersion == HttpVersionType.Http1_0)
|
||||
else if (_keepAlive && responseHeaders.HasConnection == false && _httpVersion == HttpVersionType.Http1_0)
|
||||
{
|
||||
_responseHeaders.SetRawConnection("keep-alive", _bytesConnectionKeepAlive);
|
||||
responseHeaders.SetRawConnection("keep-alive", _bytesConnectionKeepAlive);
|
||||
}
|
||||
|
||||
end.CopyFrom(_httpVersion == HttpVersionType.Http1_1 ? _bytesHttpVersion1_1 : _bytesHttpVersion1_0);
|
||||
end.CopyFrom(statusBytes);
|
||||
_responseHeaders.CopyTo(ref end);
|
||||
responseHeaders.CopyTo(ref end);
|
||||
end.CopyFrom(_bytesEndHeaders, 0, _bytesEndHeaders.Length);
|
||||
|
||||
SocketOutput.ProducingComplete(end);
|
||||
|
|
|
|||
|
|
@ -3737,6 +3737,51 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
}
|
||||
protected override void ClearFast()
|
||||
{
|
||||
if (((_bits & 1L) != 0)) _CacheControl = default(StringValues);
|
||||
if (((_bits & 2L) != 0)) _Connection = default(StringValues);
|
||||
if (((_bits & 4L) != 0)) _Date = default(StringValues);
|
||||
if (((_bits & 8L) != 0)) _KeepAlive = default(StringValues);
|
||||
if (((_bits & 16L) != 0)) _Pragma = default(StringValues);
|
||||
if (((_bits & 32L) != 0)) _Trailer = default(StringValues);
|
||||
if (((_bits & 64L) != 0)) _TransferEncoding = default(StringValues);
|
||||
if (((_bits & 128L) != 0)) _Upgrade = default(StringValues);
|
||||
if (((_bits & 256L) != 0)) _Via = default(StringValues);
|
||||
if (((_bits & 512L) != 0)) _Warning = default(StringValues);
|
||||
if (((_bits & 1024L) != 0)) _Allow = default(StringValues);
|
||||
if (((_bits & 2048L) != 0)) _ContentLength = default(StringValues);
|
||||
if (((_bits & 4096L) != 0)) _ContentType = default(StringValues);
|
||||
if (((_bits & 8192L) != 0)) _ContentEncoding = default(StringValues);
|
||||
if (((_bits & 16384L) != 0)) _ContentLanguage = default(StringValues);
|
||||
if (((_bits & 32768L) != 0)) _ContentLocation = default(StringValues);
|
||||
if (((_bits & 65536L) != 0)) _ContentMD5 = default(StringValues);
|
||||
if (((_bits & 131072L) != 0)) _ContentRange = default(StringValues);
|
||||
if (((_bits & 262144L) != 0)) _Expires = default(StringValues);
|
||||
if (((_bits & 524288L) != 0)) _LastModified = default(StringValues);
|
||||
if (((_bits & 1048576L) != 0)) _Accept = default(StringValues);
|
||||
if (((_bits & 2097152L) != 0)) _AcceptCharset = default(StringValues);
|
||||
if (((_bits & 4194304L) != 0)) _AcceptEncoding = default(StringValues);
|
||||
if (((_bits & 8388608L) != 0)) _AcceptLanguage = default(StringValues);
|
||||
if (((_bits & 16777216L) != 0)) _Authorization = default(StringValues);
|
||||
if (((_bits & 33554432L) != 0)) _Cookie = default(StringValues);
|
||||
if (((_bits & 67108864L) != 0)) _Expect = default(StringValues);
|
||||
if (((_bits & 134217728L) != 0)) _From = default(StringValues);
|
||||
if (((_bits & 268435456L) != 0)) _Host = default(StringValues);
|
||||
if (((_bits & 536870912L) != 0)) _IfMatch = default(StringValues);
|
||||
if (((_bits & 1073741824L) != 0)) _IfModifiedSince = default(StringValues);
|
||||
if (((_bits & 2147483648L) != 0)) _IfNoneMatch = default(StringValues);
|
||||
if (((_bits & 4294967296L) != 0)) _IfRange = default(StringValues);
|
||||
if (((_bits & 8589934592L) != 0)) _IfUnmodifiedSince = default(StringValues);
|
||||
if (((_bits & 17179869184L) != 0)) _MaxForwards = default(StringValues);
|
||||
if (((_bits & 34359738368L) != 0)) _ProxyAuthorization = default(StringValues);
|
||||
if (((_bits & 68719476736L) != 0)) _Referer = default(StringValues);
|
||||
if (((_bits & 137438953472L) != 0)) _Range = default(StringValues);
|
||||
if (((_bits & 274877906944L) != 0)) _TE = default(StringValues);
|
||||
if (((_bits & 549755813888L) != 0)) _Translate = default(StringValues);
|
||||
if (((_bits & 1099511627776L) != 0)) _UserAgent = default(StringValues);
|
||||
if (((_bits & 2199023255552L) != 0)) _Origin = default(StringValues);
|
||||
if (((_bits & 4398046511104L) != 0)) _AccessControlRequestMethod = default(StringValues);
|
||||
if (((_bits & 8796093022208L) != 0)) _AccessControlRequestHeaders = default(StringValues);
|
||||
|
||||
_bits = 0;
|
||||
MaybeUnknown?.Clear();
|
||||
}
|
||||
|
|
@ -8618,6 +8663,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
}
|
||||
protected override void ClearFast()
|
||||
{
|
||||
|
||||
_bits = 0;
|
||||
MaybeUnknown?.Clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
await SocketInput;
|
||||
}
|
||||
|
||||
while (!_requestProcessingStopping && !TakeMessageHeaders(SocketInput, _requestHeaders))
|
||||
InitializeHeaders();
|
||||
|
||||
while (!_requestProcessingStopping && !TakeMessageHeaders(SocketInput, FrameRequestHeaders))
|
||||
{
|
||||
if (SocketInput.RemoteIntakeFin)
|
||||
{
|
||||
|
|
@ -63,20 +65,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
|
||||
if (!_requestProcessingStopping)
|
||||
{
|
||||
var messageBody = MessageBody.For(HttpVersion, _requestHeaders, this);
|
||||
var messageBody = MessageBody.For(HttpVersion, FrameRequestHeaders, this);
|
||||
_keepAlive = messageBody.RequestKeepAlive;
|
||||
|
||||
// _duplexStream may be null if flag switched while running
|
||||
if (!ReuseStreams || _duplexStream == null)
|
||||
{
|
||||
_requestBody = new FrameRequestStream();
|
||||
_responseBody = new FrameResponseStream(this);
|
||||
_duplexStream = new FrameDuplexStream(_requestBody, _responseBody);
|
||||
}
|
||||
|
||||
RequestBody = _requestBody.StartAcceptingReads(messageBody);
|
||||
ResponseBody = _responseBody.StartAcceptingWrites();
|
||||
DuplexStream = _duplexStream;
|
||||
InitializeStreams(messageBody);
|
||||
|
||||
_abortedCts = null;
|
||||
_manuallySetRequestAbortToken = null;
|
||||
|
|
@ -101,8 +93,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
await FireOnStarting();
|
||||
}
|
||||
|
||||
_requestBody.PauseAcceptingReads();
|
||||
_responseBody.PauseAcceptingWrites();
|
||||
PauseStreams();
|
||||
|
||||
if (_onCompleted != null)
|
||||
{
|
||||
|
|
@ -114,23 +105,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
// If _requestAbort is set, the connection has already been closed.
|
||||
if (Volatile.Read(ref _requestAborted) == 0)
|
||||
{
|
||||
_responseBody.ResumeAcceptingWrites();
|
||||
ResumeStreams();
|
||||
|
||||
await ProduceEnd();
|
||||
|
||||
if (_keepAlive)
|
||||
{
|
||||
_requestBody.ResumeAcceptingReads();
|
||||
// Finish reading the request body in case the app did not.
|
||||
await messageBody.Consume();
|
||||
}
|
||||
}
|
||||
|
||||
_requestBody.StopAcceptingReads();
|
||||
_responseBody.StopAcceptingWrites();
|
||||
StopStreams();
|
||||
}
|
||||
|
||||
if (!_keepAlive)
|
||||
{
|
||||
ResetComponents(poolingPermitted: true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -144,6 +135,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
}
|
||||
finally
|
||||
{
|
||||
// Error occurred, do not return components to pool
|
||||
ResetComponents(poolingPermitted: false);
|
||||
try
|
||||
{
|
||||
_abortedCts = null;
|
||||
|
|
|
|||
|
|
@ -11,12 +11,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
{
|
||||
class FrameResponseStream : Stream
|
||||
{
|
||||
private readonly FrameContext _context;
|
||||
private FrameContext _context;
|
||||
private FrameStreamState _state;
|
||||
|
||||
public FrameResponseStream(FrameContext context)
|
||||
public FrameResponseStream()
|
||||
{
|
||||
_context = context;
|
||||
_state = FrameStreamState.Closed;
|
||||
}
|
||||
|
||||
|
|
@ -125,6 +124,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
}
|
||||
}
|
||||
|
||||
public void Initialize(FrameContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public void Uninitialize()
|
||||
{
|
||||
_context = null;
|
||||
_state = FrameStreamState.Closed;
|
||||
}
|
||||
|
||||
private Task ValidateState(CancellationToken cancellationToken)
|
||||
{
|
||||
switch (_state)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
// 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.Collections.Concurrent;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Http;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
|
||||
{
|
||||
class HttpComponentFactory : IHttpComponentFactory
|
||||
{
|
||||
private const int _maxPooledComponents = 128;
|
||||
private ConcurrentQueue<Streams> _streamPool = new ConcurrentQueue<Streams>();
|
||||
private ConcurrentQueue<Headers> _headerPool = new ConcurrentQueue<Headers>();
|
||||
|
||||
public Streams CreateStreams(FrameContext owner)
|
||||
{
|
||||
Streams streams;
|
||||
|
||||
if (!_streamPool.TryDequeue(out streams))
|
||||
{
|
||||
streams = new Streams();
|
||||
}
|
||||
|
||||
streams.Initialize(owner);
|
||||
|
||||
return streams;
|
||||
}
|
||||
|
||||
public void DisposeStreams(Streams streams, bool poolingPermitted)
|
||||
{
|
||||
if (poolingPermitted && _streamPool.Count < _maxPooledComponents)
|
||||
{
|
||||
streams.Uninitialize();
|
||||
|
||||
_streamPool.Enqueue(streams);
|
||||
}
|
||||
}
|
||||
|
||||
public Headers CreateHeaders(DateHeaderValueManager dateValueManager)
|
||||
{
|
||||
Headers headers;
|
||||
|
||||
if (!_headerPool.TryDequeue(out headers))
|
||||
{
|
||||
headers = new Headers();
|
||||
}
|
||||
|
||||
headers.Initialize(dateValueManager);
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void DisposeHeaders(Headers headers, bool poolingPermitted)
|
||||
{
|
||||
if (poolingPermitted && _headerPool.Count < _maxPooledComponents)
|
||||
{
|
||||
headers.Uninitialize();
|
||||
|
||||
_headerPool.Enqueue(headers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class Headers
|
||||
{
|
||||
public static readonly byte[] BytesServer = Encoding.ASCII.GetBytes("\r\nServer: Kestrel");
|
||||
|
||||
public readonly FrameRequestHeaders RequestHeaders = new FrameRequestHeaders();
|
||||
public readonly FrameResponseHeaders ResponseHeaders = new FrameResponseHeaders();
|
||||
|
||||
public Headers()
|
||||
{
|
||||
RequestHeaders = new FrameRequestHeaders();
|
||||
ResponseHeaders = new FrameResponseHeaders();
|
||||
}
|
||||
|
||||
public void Initialize(DateHeaderValueManager dateValueManager)
|
||||
{
|
||||
ResponseHeaders.SetRawDate(
|
||||
dateValueManager.GetDateHeaderValue(),
|
||||
dateValueManager.GetDateHeaderValueBytes());
|
||||
ResponseHeaders.SetRawServer("Kestrel", BytesServer);
|
||||
}
|
||||
|
||||
public void Uninitialize()
|
||||
{
|
||||
RequestHeaders.Reset();
|
||||
ResponseHeaders.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
internal class Streams
|
||||
{
|
||||
public readonly FrameRequestStream RequestBody;
|
||||
public readonly FrameResponseStream ResponseBody;
|
||||
public readonly FrameDuplexStream DuplexStream;
|
||||
|
||||
public Streams()
|
||||
{
|
||||
RequestBody = new FrameRequestStream();
|
||||
ResponseBody = new FrameResponseStream();
|
||||
DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody);
|
||||
}
|
||||
|
||||
public void Initialize(FrameContext renter)
|
||||
{
|
||||
ResponseBody.Initialize(renter);
|
||||
}
|
||||
|
||||
public void Uninitialize()
|
||||
{
|
||||
ResponseBody.Uninitialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// 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 Microsoft.AspNetCore.Server.Kestrel.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
|
||||
{
|
||||
interface IHttpComponentFactory
|
||||
{
|
||||
Streams CreateStreams(FrameContext owner);
|
||||
|
||||
void DisposeStreams(Streams streams, bool poolingPermitted);
|
||||
|
||||
Headers CreateHeaders(DateHeaderValueManager dateValueManager);
|
||||
|
||||
void DisposeHeaders(Headers headers, bool poolingPermitted);
|
||||
}
|
||||
}
|
||||
|
|
@ -56,6 +56,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
var information = (KestrelServerInformation)Features.Get<IKestrelServerInformation>();
|
||||
var dateHeaderValueManager = new DateHeaderValueManager();
|
||||
var trace = new KestrelTrace(_logger);
|
||||
var componentFactory = new HttpComponentFactory();
|
||||
var engine = new KestrelEngine(new ServiceContext
|
||||
{
|
||||
FrameFactory = (context, remoteEP, localEP, prepareRequest) =>
|
||||
|
|
@ -68,7 +69,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
DateHeaderValueManager = dateHeaderValueManager,
|
||||
ConnectionFilter = information.ConnectionFilter,
|
||||
NoDelay = information.NoDelay,
|
||||
ReuseStreams = information.ReuseStreams
|
||||
ReuseStreams = information.ReuseStreams,
|
||||
HttpComponentFactory = componentFactory
|
||||
});
|
||||
|
||||
_disposables.Push(engine);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
ConnectionFilter = context.ConnectionFilter;
|
||||
NoDelay = context.NoDelay;
|
||||
ReuseStreams = context.ReuseStreams;
|
||||
HttpComponentFactory = context.HttpComponentFactory;
|
||||
}
|
||||
|
||||
public IApplicationLifetime AppLifetime { get; set; }
|
||||
|
|
@ -44,5 +45,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
public bool NoDelay { get; set; }
|
||||
|
||||
public bool ReuseStreams { get; set; }
|
||||
|
||||
internal IHttpComponentFactory HttpComponentFactory { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Server.Kestrel;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Http;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Infrastructure;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -18,9 +19,12 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var connectionContext = new ConnectionContext
|
||||
{
|
||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000")
|
||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||
HttpComponentFactory = new HttpComponentFactory()
|
||||
};
|
||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||
var frame = new Frame<object>(application: null, context: connectionContext)
|
||||
.InitializeHeaders();
|
||||
|
||||
IDictionary<string, StringValues> headers = frame.ResponseHeaders;
|
||||
|
||||
Assert.Equal(2, headers.Count);
|
||||
|
|
@ -46,10 +50,12 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var connectionContext = new ConnectionContext
|
||||
{
|
||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000")
|
||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||
HttpComponentFactory = new HttpComponentFactory()
|
||||
};
|
||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||
|
||||
var frame = new Frame<object>(application: null, context: connectionContext)
|
||||
.InitializeHeaders();
|
||||
|
||||
Assert.True(frame.ResponseHeaders.Count > 0);
|
||||
|
||||
frame.ResponseHeaders.Clear();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
Log = new TestKestrelTrace();
|
||||
ThreadPool = new LoggingThreadPool(Log);
|
||||
DateHeaderValueManager = new TestDateHeaderValueManager();
|
||||
HttpComponentFactory = new HttpComponentFactory();
|
||||
}
|
||||
|
||||
public RequestDelegate App
|
||||
|
|
|
|||
|
|
@ -366,7 +366,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
return MaybeUnknown?.Remove(key) ?? false;
|
||||
}}
|
||||
protected override void ClearFast()
|
||||
{{
|
||||
{{{(loop.ClassName != "FrameRequestHeaders" ? "" : Each(loop.Headers, header => $@"
|
||||
if ({header.TestBit()}) _{header.Identifier} = default(StringValues);"))}
|
||||
|
||||
_bits = 0;
|
||||
MaybeUnknown?.Clear();
|
||||
}}
|
||||
|
|
|
|||
Loading…
Reference in New Issue