Reuse headers to prevent values moving to higher GC gens

This commit is contained in:
Ben Adams 2016-02-01 09:40:10 +00:00
parent dfcd6a6227
commit c293bbbd1a
11 changed files with 311 additions and 71 deletions

View File

@ -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[] _bytesHttpVersion1_1 = Encoding.ASCII.GetBytes("HTTP/1.1 ");
private static readonly byte[] _bytesContentLengthZero = Encoding.ASCII.GetBytes("\r\nContent-Length: 0"); private static readonly byte[] _bytesContentLengthZero = Encoding.ASCII.GetBytes("\r\nContent-Length: 0");
private static readonly byte[] _bytesSpace = Encoding.ASCII.GetBytes(" "); 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 readonly byte[] _bytesEndHeaders = Encoding.ASCII.GetBytes("\r\n\r\n");
private static Vector<byte> _vectorCRs = new Vector<byte>((byte)'\r'); 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 _onStartingSync = new Object();
private readonly object _onCompletedSync = 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; protected List<KeyValuePair<Func<object, Task>, object>> _onStarting;
@ -60,10 +59,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
protected CancellationTokenSource _abortedCts; protected CancellationTokenSource _abortedCts;
protected CancellationToken? _manuallySetRequestAbortToken; protected CancellationToken? _manuallySetRequestAbortToken;
internal FrameRequestStream _requestBody;
internal FrameResponseStream _responseBody;
internal FrameDuplexStream _duplexStream;
protected bool _responseStarted; protected bool _responseStarted;
protected bool _keepAlive; protected bool _keepAlive;
private bool _autoChunk; private bool _autoChunk;
@ -92,12 +87,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
_localEndPoint = localEndPoint; _localEndPoint = localEndPoint;
_prepareRequest = prepareRequest; _prepareRequest = prepareRequest;
_pathBase = context.ServerAddress.PathBase; _pathBase = context.ServerAddress.PathBase;
if (ReuseStreams)
{
_requestBody = new FrameRequestStream();
_responseBody = new FrameResponseStream(this);
_duplexStream = new FrameDuplexStream(_requestBody, _responseBody);
}
FrameControl = this; FrameControl = this;
Reset(); Reset();
@ -197,8 +186,48 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
get { return _responseStarted; } 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() public void Reset()
{ {
ResetComponents(poolingPermitted: true);
_onStarting = null; _onStarting = null;
_onCompleted = null; _onCompleted = null;
@ -207,8 +236,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
_autoChunk = false; _autoChunk = false;
_applicationException = null; _applicationException = null;
_requestHeaders.Reset();
ResetResponseHeaders();
ResetFeatureCollection(); ResetFeatureCollection();
Scheme = null; Scheme = null;
@ -218,13 +245,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
Path = null; Path = null;
QueryString = null; QueryString = null;
_httpVersion = HttpVersionType.Unknown; _httpVersion = HttpVersionType.Unknown;
RequestHeaders = _requestHeaders;
RequestBody = null;
StatusCode = 200; StatusCode = 200;
ReasonPhrase = null; ReasonPhrase = null;
ResponseHeaders = _responseHeaders;
ResponseBody = null;
DuplexStream = null;
var httpConnectionFeature = this as IHttpConnectionFeature; var httpConnectionFeature = this as IHttpConnectionFeature;
httpConnectionFeature.RemoteIpAddress = _remoteEndPoint?.Address; httpConnectionFeature.RemoteIpAddress = _remoteEndPoint?.Address;
@ -239,15 +261,26 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
_abortedCts = null; _abortedCts = null;
} }
public void ResetResponseHeaders() protected void ResetComponents(bool poolingPermitted)
{ {
_responseHeaders.Reset(); if (_frameHeaders != null)
_responseHeaders.SetRawDate( {
DateHeaderValueManager.GetDateHeaderValue(), RequestHeaders = null;
DateHeaderValueManager.GetDateHeaderValueBytes()); ResponseHeaders = null;
_responseHeaders.SetRawServer( var frameHeaders = _frameHeaders;
"Kestrel", _frameHeaders = null;
_bytesServer); 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> /// <summary>
@ -292,8 +325,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{ {
_requestProcessingStopping = true; _requestProcessingStopping = true;
_requestBody?.Abort(); _frameStreams?.RequestBody.Abort();
_responseBody?.Abort(); _frameStreams?.ResponseBody.Abort();
try try
{ {
@ -560,8 +593,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
StatusCode = 500; StatusCode = 500;
ReasonPhrase = null; ReasonPhrase = null;
ResetResponseHeaders(); var responseHeaders = _frameHeaders.ResponseHeaders;
_responseHeaders.SetRawContentLength("0", _bytesContentLengthZero); 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) bool appCompleted)
{ {
var end = SocketOutput.ProducingStart(); var end = SocketOutput.ProducingStart();
var responseHeaders = _frameHeaders.ResponseHeaders;
if (_keepAlive) if (_keepAlive)
{ {
foreach (var connectionValue in _responseHeaders.HeaderConnection) foreach (var connectionValue in responseHeaders.HeaderConnection)
{ {
if (connectionValue.IndexOf("close", StringComparison.OrdinalIgnoreCase) != -1) 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) if (appCompleted)
{ {
@ -636,7 +679,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{ {
// Since the app has completed and we are only now generating // Since the app has completed and we are only now generating
// the headers we can safely set the Content-Length to 0. // the headers we can safely set the Content-Length to 0.
_responseHeaders.SetRawContentLength("0", _bytesContentLengthZero); responseHeaders.SetRawContentLength("0", _bytesContentLengthZero);
} }
} }
else else
@ -644,7 +687,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
if (_httpVersion == HttpVersionType.Http1_1) if (_httpVersion == HttpVersionType.Http1_1)
{ {
_autoChunk = true; _autoChunk = true;
_responseHeaders.SetRawTransferEncoding("chunked", _bytesTransferEncodingChunked); responseHeaders.SetRawTransferEncoding("chunked", _bytesTransferEncodingChunked);
} }
else 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(_httpVersion == HttpVersionType.Http1_1 ? _bytesHttpVersion1_1 : _bytesHttpVersion1_0);
end.CopyFrom(statusBytes); end.CopyFrom(statusBytes);
_responseHeaders.CopyTo(ref end); responseHeaders.CopyTo(ref end);
end.CopyFrom(_bytesEndHeaders, 0, _bytesEndHeaders.Length); end.CopyFrom(_bytesEndHeaders, 0, _bytesEndHeaders.Length);
SocketOutput.ProducingComplete(end); SocketOutput.ProducingComplete(end);

View File

@ -3737,6 +3737,51 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
} }
protected override void ClearFast() 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; _bits = 0;
MaybeUnknown?.Clear(); MaybeUnknown?.Clear();
} }
@ -8618,6 +8663,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
} }
protected override void ClearFast() protected override void ClearFast()
{ {
_bits = 0; _bits = 0;
MaybeUnknown?.Clear(); MaybeUnknown?.Clear();
} }

View File

@ -52,7 +52,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
await SocketInput; await SocketInput;
} }
while (!_requestProcessingStopping && !TakeMessageHeaders(SocketInput, _requestHeaders)) InitializeHeaders();
while (!_requestProcessingStopping && !TakeMessageHeaders(SocketInput, FrameRequestHeaders))
{ {
if (SocketInput.RemoteIntakeFin) if (SocketInput.RemoteIntakeFin)
{ {
@ -63,20 +65,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
if (!_requestProcessingStopping) if (!_requestProcessingStopping)
{ {
var messageBody = MessageBody.For(HttpVersion, _requestHeaders, this); var messageBody = MessageBody.For(HttpVersion, FrameRequestHeaders, this);
_keepAlive = messageBody.RequestKeepAlive; _keepAlive = messageBody.RequestKeepAlive;
// _duplexStream may be null if flag switched while running InitializeStreams(messageBody);
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;
_abortedCts = null; _abortedCts = null;
_manuallySetRequestAbortToken = null; _manuallySetRequestAbortToken = null;
@ -101,8 +93,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
await FireOnStarting(); await FireOnStarting();
} }
_requestBody.PauseAcceptingReads(); PauseStreams();
_responseBody.PauseAcceptingWrites();
if (_onCompleted != null) if (_onCompleted != null)
{ {
@ -114,23 +105,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
// If _requestAbort is set, the connection has already been closed. // If _requestAbort is set, the connection has already been closed.
if (Volatile.Read(ref _requestAborted) == 0) if (Volatile.Read(ref _requestAborted) == 0)
{ {
_responseBody.ResumeAcceptingWrites(); ResumeStreams();
await ProduceEnd(); await ProduceEnd();
if (_keepAlive) if (_keepAlive)
{ {
_requestBody.ResumeAcceptingReads();
// Finish reading the request body in case the app did not. // Finish reading the request body in case the app did not.
await messageBody.Consume(); await messageBody.Consume();
} }
} }
_requestBody.StopAcceptingReads(); StopStreams();
_responseBody.StopAcceptingWrites();
} }
if (!_keepAlive) if (!_keepAlive)
{ {
ResetComponents(poolingPermitted: true);
return; return;
} }
} }
@ -144,6 +135,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
} }
finally finally
{ {
// Error occurred, do not return components to pool
ResetComponents(poolingPermitted: false);
try try
{ {
_abortedCts = null; _abortedCts = null;

View File

@ -11,12 +11,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{ {
class FrameResponseStream : Stream class FrameResponseStream : Stream
{ {
private readonly FrameContext _context; private FrameContext _context;
private FrameStreamState _state; private FrameStreamState _state;
public FrameResponseStream(FrameContext context) public FrameResponseStream()
{ {
_context = context;
_state = FrameStreamState.Closed; _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) private Task ValidateState(CancellationToken cancellationToken)
{ {
switch (_state) switch (_state)

View File

@ -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();
}
}
}

View File

@ -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);
}
}

View File

@ -56,6 +56,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
var information = (KestrelServerInformation)Features.Get<IKestrelServerInformation>(); var information = (KestrelServerInformation)Features.Get<IKestrelServerInformation>();
var dateHeaderValueManager = new DateHeaderValueManager(); var dateHeaderValueManager = new DateHeaderValueManager();
var trace = new KestrelTrace(_logger); var trace = new KestrelTrace(_logger);
var componentFactory = new HttpComponentFactory();
var engine = new KestrelEngine(new ServiceContext var engine = new KestrelEngine(new ServiceContext
{ {
FrameFactory = (context, remoteEP, localEP, prepareRequest) => FrameFactory = (context, remoteEP, localEP, prepareRequest) =>
@ -68,7 +69,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel
DateHeaderValueManager = dateHeaderValueManager, DateHeaderValueManager = dateHeaderValueManager,
ConnectionFilter = information.ConnectionFilter, ConnectionFilter = information.ConnectionFilter,
NoDelay = information.NoDelay, NoDelay = information.NoDelay,
ReuseStreams = information.ReuseStreams ReuseStreams = information.ReuseStreams,
HttpComponentFactory = componentFactory
}); });
_disposables.Push(engine); _disposables.Push(engine);

View File

@ -27,6 +27,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
ConnectionFilter = context.ConnectionFilter; ConnectionFilter = context.ConnectionFilter;
NoDelay = context.NoDelay; NoDelay = context.NoDelay;
ReuseStreams = context.ReuseStreams; ReuseStreams = context.ReuseStreams;
HttpComponentFactory = context.HttpComponentFactory;
} }
public IApplicationLifetime AppLifetime { get; set; } public IApplicationLifetime AppLifetime { get; set; }
@ -44,5 +45,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
public bool NoDelay { get; set; } public bool NoDelay { get; set; }
public bool ReuseStreams { get; set; } public bool ReuseStreams { get; set; }
internal IHttpComponentFactory HttpComponentFactory { get; set; }
} }
} }

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Server.Kestrel; using Microsoft.AspNetCore.Server.Kestrel;
using Microsoft.AspNetCore.Server.Kestrel.Http; using Microsoft.AspNetCore.Server.Kestrel.Http;
using Microsoft.AspNetCore.Server.Kestrel.Infrastructure;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Xunit; using Xunit;
@ -18,9 +19,12 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
var connectionContext = new ConnectionContext var connectionContext = new ConnectionContext
{ {
DateHeaderValueManager = new DateHeaderValueManager(), 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; IDictionary<string, StringValues> headers = frame.ResponseHeaders;
Assert.Equal(2, headers.Count); Assert.Equal(2, headers.Count);
@ -46,10 +50,12 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
var connectionContext = new ConnectionContext var connectionContext = new ConnectionContext
{ {
DateHeaderValueManager = new DateHeaderValueManager(), 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); Assert.True(frame.ResponseHeaders.Count > 0);
frame.ResponseHeaders.Clear(); frame.ResponseHeaders.Clear();

View File

@ -18,6 +18,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
Log = new TestKestrelTrace(); Log = new TestKestrelTrace();
ThreadPool = new LoggingThreadPool(Log); ThreadPool = new LoggingThreadPool(Log);
DateHeaderValueManager = new TestDateHeaderValueManager(); DateHeaderValueManager = new TestDateHeaderValueManager();
HttpComponentFactory = new HttpComponentFactory();
} }
public RequestDelegate App public RequestDelegate App

View File

@ -366,7 +366,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
return MaybeUnknown?.Remove(key) ?? false; return MaybeUnknown?.Remove(key) ?? false;
}} }}
protected override void ClearFast() protected override void ClearFast()
{{ {{{(loop.ClassName != "FrameRequestHeaders" ? "" : Each(loop.Headers, header => $@"
if ({header.TestBit()}) _{header.Identifier} = default(StringValues);"))}
_bits = 0; _bits = 0;
MaybeUnknown?.Clear(); MaybeUnknown?.Clear();
}} }}