Specialized struct generics rather than interface (#1640)

Changed the IHttpParser interface to be generic. This lets use a struct to 
get better code generation and also should allow us to inline calls back into
the handler from the parser.
This commit is contained in:
Ben Adams 2017-04-11 03:30:18 +01:00 committed by David Fowler
parent 1faaefef30
commit d29e4d4cf0
21 changed files with 78 additions and 62 deletions

View File

@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
return WriteAsync(default(ArraySegment<byte>), chunk: false, cancellationToken: cancellationToken); return WriteAsync(default(ArraySegment<byte>), chunk: false, cancellationToken: cancellationToken);
} }
public void Write<T>(Action<WritableBuffer, T> callback, T state) public void Write<T>(Action<WritableBuffer, T> callback, T state) where T : struct
{ {
lock (_sync) lock (_sync)
{ {

View File

@ -26,7 +26,7 @@ using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{ {
public abstract partial class Frame : IFrameControl, IHttpRequestLineHandler, IHttpHeadersHandler public abstract partial class Frame : IFrameControl
{ {
private const byte ByteAsterisk = (byte)'*'; private const byte ByteAsterisk = (byte)'*';
private const byte ByteForwardSlash = (byte)'/'; private const byte ByteForwardSlash = (byte)'/';
@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private static readonly ArraySegment<byte> _endChunkedResponseBytes = CreateAsciiByteArraySegment("0\r\n\r\n"); private static readonly ArraySegment<byte> _endChunkedResponseBytes = CreateAsciiByteArraySegment("0\r\n\r\n");
private static readonly ArraySegment<byte> _continueBytes = CreateAsciiByteArraySegment("HTTP/1.1 100 Continue\r\n\r\n"); private static readonly ArraySegment<byte> _continueBytes = CreateAsciiByteArraySegment("HTTP/1.1 100 Continue\r\n\r\n");
private static readonly Action<WritableBuffer, Frame> _writeHeaders = WriteResponseHeaders; private static readonly Action<WritableBuffer, FrameAdapter> _writeHeaders = WriteResponseHeaders;
private static readonly byte[] _bytesConnectionClose = Encoding.ASCII.GetBytes("\r\nConnection: close"); private static readonly byte[] _bytesConnectionClose = Encoding.ASCII.GetBytes("\r\nConnection: close");
private static readonly byte[] _bytesConnectionKeepAlive = Encoding.ASCII.GetBytes("\r\nConnection: keep-alive"); private static readonly byte[] _bytesConnectionKeepAlive = Encoding.ASCII.GetBytes("\r\nConnection: keep-alive");
@ -80,7 +80,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
protected long _responseBytesWritten; protected long _responseBytesWritten;
private readonly FrameContext _frameContext; private readonly FrameContext _frameContext;
private readonly IHttpParser _parser; private readonly IHttpParser<FrameAdapter> _parser;
public Frame(FrameContext frameContext) public Frame(FrameContext frameContext)
{ {
@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
ServerOptions = ServiceContext.ServerOptions; ServerOptions = ServiceContext.ServerOptions;
_parser = ServiceContext.HttpParserFactory(this); _parser = ServiceContext.HttpParserFactory(new FrameAdapter(this));
FrameControl = this; FrameControl = this;
_keepAliveMilliseconds = (long)ServerOptions.Limits.KeepAliveTimeout.TotalMilliseconds; _keepAliveMilliseconds = (long)ServerOptions.Limits.KeepAliveTimeout.TotalMilliseconds;
@ -988,11 +988,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
responseHeaders.SetRawDate(dateHeaderValues.String, dateHeaderValues.Bytes); responseHeaders.SetRawDate(dateHeaderValues.String, dateHeaderValues.Bytes);
} }
Output.Write(_writeHeaders, this); Output.Write(_writeHeaders, new FrameAdapter(this));
} }
private static void WriteResponseHeaders(WritableBuffer writableBuffer, Frame frame) private static void WriteResponseHeaders(WritableBuffer writableBuffer, FrameAdapter frameAdapter)
{ {
var frame = frameAdapter.Frame;
var writer = new WritableBufferWriter(writableBuffer); var writer = new WritableBufferWriter(writableBuffer);
var responseHeaders = frame.FrameResponseHeaders; var responseHeaders = frame.FrameResponseHeaders;
@ -1050,7 +1051,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
overLength = true; overLength = true;
} }
var result = _parser.ParseRequestLine(this, buffer, out consumed, out examined); var result = _parser.ParseRequestLine(new FrameAdapter(this), buffer, out consumed, out examined);
if (!result && overLength) if (!result && overLength)
{ {
RejectRequest(RequestRejectionReason.RequestLineTooLong); RejectRequest(RequestRejectionReason.RequestLineTooLong);
@ -1072,7 +1073,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
overLength = true; overLength = true;
} }
var result = _parser.ParseHeaders(this, buffer, out consumed, out examined, out var consumedBytes); var result = _parser.ParseHeaders(new FrameAdapter(this), buffer, out consumed, out examined, out var consumedBytes);
_remainingRequestHeadersBytesAllowed -= consumedBytes; _remainingRequestHeadersBytesAllowed -= consumedBytes;
if (!result && overLength) if (!result && overLength)

View File

@ -0,0 +1,23 @@
// 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.Internal.System;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
public struct FrameAdapter : IHttpRequestLineHandler, IHttpHeadersHandler
{
public Frame Frame;
public FrameAdapter(Frame frame)
{
Frame = frame;
}
public void OnHeader(Span<byte> name, Span<byte> value)
=> Frame.OnHeader(name, value);
public void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
=> Frame.OnStartLine(method, version, target, path, query, customMethod, pathEncoded);
}
}

View File

@ -9,7 +9,7 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{ {
public class HttpParser : IHttpParser public class HttpParser<TRequestHandler> : IHttpParser<TRequestHandler> where TRequestHandler : IHttpHeadersHandler, IHttpRequestLineHandler
{ {
public HttpParser(IKestrelTrace log) public HttpParser(IKestrelTrace log)
{ {
@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private const byte ByteQuestionMark = (byte)'?'; private const byte ByteQuestionMark = (byte)'?';
private const byte BytePercentage = (byte)'%'; private const byte BytePercentage = (byte)'%';
public unsafe bool ParseRequestLine(IHttpRequestLineHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) public unsafe bool ParseRequestLine(TRequestHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined)
{ {
consumed = buffer.Start; consumed = buffer.Start;
examined = buffer.End; examined = buffer.End;
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return true; return true;
} }
private unsafe void ParseRequestLine(IHttpRequestLineHandler handler, byte* data, int length) private unsafe void ParseRequestLine(TRequestHandler handler, byte* data, int length)
{ {
int offset; int offset;
Span<byte> customMethod = default(Span<byte>); Span<byte> customMethod = default(Span<byte>);
@ -183,7 +183,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
handler.OnStartLine(method, httpVersion, targetBuffer, pathBuffer, query, customMethod, pathEncoded); handler.OnStartLine(method, httpVersion, targetBuffer, pathBuffer, query, customMethod, pathEncoded);
} }
public unsafe bool ParseHeaders(IHttpHeadersHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes) public unsafe bool ParseHeaders(TRequestHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes)
{ {
consumed = buffer.Start; consumed = buffer.Start;
examined = buffer.End; examined = buffer.End;
@ -346,7 +346,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe void TakeSingleHeader(byte* headerLine, int length, IHttpHeadersHandler handler) private unsafe void TakeSingleHeader(byte* headerLine, int length, TRequestHandler handler)
{ {
// Skip CR, LF from end position // Skip CR, LF from end position
var valueEnd = length - 3; var valueEnd = length - 3;

View File

@ -5,11 +5,11 @@ using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{ {
public interface IHttpParser public interface IHttpParser<TRequestHandler> where TRequestHandler : IHttpHeadersHandler, IHttpRequestLineHandler
{ {
bool ParseRequestLine(IHttpRequestLineHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined); bool ParseRequestLine(TRequestHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined);
bool ParseHeaders(IHttpHeadersHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes); bool ParseHeaders(TRequestHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes);
void Reset(); void Reset();
} }

View File

@ -17,6 +17,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
Task WriteAsync(ArraySegment<byte> buffer, bool chunk = false, CancellationToken cancellationToken = default(CancellationToken)); Task WriteAsync(ArraySegment<byte> buffer, bool chunk = false, CancellationToken cancellationToken = default(CancellationToken));
void Flush(); void Flush();
Task FlushAsync(CancellationToken cancellationToken = default(CancellationToken)); Task FlushAsync(CancellationToken cancellationToken = default(CancellationToken));
void Write<T>(Action<WritableBuffer, T> write, T state); void Write<T>(Action<WritableBuffer, T> write, T state) where T : struct;
} }
} }

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
public IThreadPool ThreadPool { get; set; } public IThreadPool ThreadPool { get; set; }
public Func<Frame, IHttpParser> HttpParserFactory { get; set; } public Func<FrameAdapter, IHttpParser<FrameAdapter>> HttpParserFactory { get; set; }
public DateHeaderValueManager DateHeaderValueManager { get; set; } public DateHeaderValueManager DateHeaderValueManager { get; set; }

View File

@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
var serviceContext = new ServiceContext var serviceContext = new ServiceContext
{ {
Log = trace, Log = trace,
HttpParserFactory = frame => new HttpParser(frame.ServiceContext.Log), HttpParserFactory = frameParser => new HttpParser<FrameAdapter>(frameParser.Frame.ServiceContext.Log),
ThreadPool = threadPool, ThreadPool = threadPool,
DateHeaderValueManager = _dateHeaderValueManager, DateHeaderValueManager = _dateHeaderValueManager,
ServerOptions = Options ServerOptions = Options

View File

@ -256,28 +256,5 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
"42,000", "42,000",
"42.000", "42.000",
}; };
private class NoopHttpParser : IHttpParser
{
public bool ParseHeaders(IHttpHeadersHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes)
{
consumed = buffer.Start;
examined = buffer.End;
consumedBytes = 0;
return false;
}
public bool ParseRequestLine(IHttpRequestLineHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined)
{
consumed = buffer.Start;
examined = buffer.End;
return false;
}
public void Reset()
{
}
}
} }
} }

View File

@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System; using Microsoft.AspNetCore.Server.Kestrel.Internal.System;
@ -418,7 +417,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Assert.Equal(buffer.End, examined); Assert.Equal(buffer.End, examined);
} }
private IHttpParser CreateParser(IKestrelTrace log) => new HttpParser(log); private IHttpParser<RequestHandler> CreateParser(IKestrelTrace log) => new HttpParser<RequestHandler>(log);
public static IEnumerable<string[]> RequestLineValidData => HttpParsingData.RequestLineValidData; public static IEnumerable<string[]> RequestLineValidData => HttpParsingData.RequestLineValidData;

View File

@ -38,11 +38,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var called = false; var called = false;
((ISocketOutput)socketOutput).Write<object>((buffer, state) => ((ISocketOutput)socketOutput).Write((buffer, state) =>
{ {
called = true; called = true;
}, },
null); 0);
Assert.False(called); Assert.False(called);
} }

View File

@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
var serviceContext = new ServiceContext var serviceContext = new ServiceContext
{ {
HttpParserFactory = _ => NullParser.Instance, HttpParserFactory = _ => NullParser<FrameAdapter>.Instance,
ServerOptions = new KestrelServerOptions() ServerOptions = new KestrelServerOptions()
}; };
var frameContext = new FrameContext var frameContext = new FrameContext

View File

@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
var serviceContext = new ServiceContext var serviceContext = new ServiceContext
{ {
HttpParserFactory = _ => NullParser.Instance, HttpParserFactory = _ => NullParser<FrameAdapter>.Instance,
ServerOptions = new KestrelServerOptions() ServerOptions = new KestrelServerOptions()
}; };
var frameContext = new FrameContext var frameContext = new FrameContext

View File

@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
DateHeaderValueManager = new DateHeaderValueManager(), DateHeaderValueManager = new DateHeaderValueManager(),
ServerOptions = new KestrelServerOptions(), ServerOptions = new KestrelServerOptions(),
Log = new MockTrace(), Log = new MockTrace(),
HttpParserFactory = f => new HttpParser(log: null) HttpParserFactory = f => new HttpParser<FrameAdapter>(log: null)
}; };
var frameContext = new FrameContext var frameContext = new FrameContext
{ {

View File

@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
public class KestrelHttpParserBenchmark : IHttpRequestLineHandler, IHttpHeadersHandler public class KestrelHttpParserBenchmark : IHttpRequestLineHandler, IHttpHeadersHandler
{ {
private readonly HttpParser _parser = new HttpParser(log: null); private readonly HttpParser<Adapter> _parser = new HttpParser<Adapter>(log: null);
private ReadableBuffer _buffer; private ReadableBuffer _buffer;
@ -53,14 +53,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
private void ParseData() private void ParseData()
{ {
if (!_parser.ParseRequestLine(this, _buffer, out var consumed, out var examined)) if (!_parser.ParseRequestLine(new Adapter(this), _buffer, out var consumed, out var examined))
{ {
ErrorUtilities.ThrowInvalidRequestHeaders(); ErrorUtilities.ThrowInvalidRequestHeaders();
} }
_buffer = _buffer.Slice(consumed, _buffer.End); _buffer = _buffer.Slice(consumed, _buffer.End);
if (!_parser.ParseHeaders(this, _buffer, out consumed, out examined, out var consumedBytes)) if (!_parser.ParseHeaders(new Adapter(this), _buffer, out consumed, out examined, out var consumedBytes))
{ {
ErrorUtilities.ThrowInvalidRequestHeaders(); ErrorUtilities.ThrowInvalidRequestHeaders();
} }
@ -73,5 +73,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
public void OnHeader(Span<byte> name, Span<byte> value) public void OnHeader(Span<byte> name, Span<byte> value)
{ {
} }
private struct Adapter : IHttpRequestLineHandler, IHttpHeadersHandler
{
public KestrelHttpParserBenchmark RequestHandler;
public Adapter(KestrelHttpParserBenchmark requestHandler)
{
RequestHandler = requestHandler;
}
public void OnHeader(Span<byte> name, Span<byte> value)
=> RequestHandler.OnHeader(name, value);
public void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
=> RequestHandler.OnStartLine(method, version, target, path, query, customMethod, pathEncoded);
}
} }
} }

View File

@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
namespace Microsoft.AspNetCore.Server.Kestrel.Performance namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
public class NullParser : IHttpParser public class NullParser<TRequestHandler> : IHttpParser<TRequestHandler> where TRequestHandler : struct, IHttpHeadersHandler, IHttpRequestLineHandler
{ {
private readonly byte[] _startLine = Encoding.ASCII.GetBytes("GET /plaintext HTTP/1.1\r\n"); private readonly byte[] _startLine = Encoding.ASCII.GetBytes("GET /plaintext HTTP/1.1\r\n");
private readonly byte[] _target = Encoding.ASCII.GetBytes("/plaintext"); private readonly byte[] _target = Encoding.ASCII.GetBytes("/plaintext");
@ -19,9 +19,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
private readonly byte[] _connectionHeaderName = Encoding.ASCII.GetBytes("Connection"); private readonly byte[] _connectionHeaderName = Encoding.ASCII.GetBytes("Connection");
private readonly byte[] _connectionHeaderValue = Encoding.ASCII.GetBytes("keep-alive"); private readonly byte[] _connectionHeaderValue = Encoding.ASCII.GetBytes("keep-alive");
public static readonly NullParser Instance = new NullParser(); public static readonly NullParser<FrameAdapter> Instance = new NullParser<FrameAdapter>();
public bool ParseHeaders(IHttpHeadersHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes) public bool ParseHeaders(TRequestHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes)
{ {
handler.OnHeader(new Span<byte>(_hostHeaderName), new Span<byte>(_hostHeaderValue)); handler.OnHeader(new Span<byte>(_hostHeaderName), new Span<byte>(_hostHeaderValue));
handler.OnHeader(new Span<byte>(_acceptHeaderName), new Span<byte>(_acceptHeaderValue)); handler.OnHeader(new Span<byte>(_acceptHeaderName), new Span<byte>(_acceptHeaderValue));
@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
return true; return true;
} }
public bool ParseRequestLine(IHttpRequestLineHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) public bool ParseRequestLine(TRequestHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined)
{ {
handler.OnStartLine(HttpMethod.Get, handler.OnStartLine(HttpMethod.Get,
HttpVersion.Http11, HttpVersion.Http11,

View File

@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
var serviceContext = new ServiceContext var serviceContext = new ServiceContext
{ {
HttpParserFactory = f => new HttpParser(f.ServiceContext.Log), HttpParserFactory = f => new HttpParser<FrameAdapter>(f.Frame.ServiceContext.Log),
ServerOptions = new KestrelServerOptions() ServerOptions = new KestrelServerOptions()
}; };
var frameContext = new FrameContext var frameContext = new FrameContext

View File

@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
var serviceContext = new ServiceContext var serviceContext = new ServiceContext
{ {
HttpParserFactory = f => new HttpParser(f.ServiceContext.Log), HttpParserFactory = f => new HttpParser<FrameAdapter>(f.Frame.ServiceContext.Log),
ServerOptions = new KestrelServerOptions() ServerOptions = new KestrelServerOptions()
}; };
var frameContext = new FrameContext var frameContext = new FrameContext

View File

@ -120,7 +120,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
DateHeaderValueManager = new DateHeaderValueManager(), DateHeaderValueManager = new DateHeaderValueManager(),
ServerOptions = new KestrelServerOptions(), ServerOptions = new KestrelServerOptions(),
Log = new MockTrace(), Log = new MockTrace(),
HttpParserFactory = f => new HttpParser(log: null) HttpParserFactory = f => new HttpParser<FrameAdapter>(log: null)
}; };
var frameContext = new FrameContext var frameContext = new FrameContext

View File

@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Testing
return TaskCache.CompletedTask; return TaskCache.CompletedTask;
} }
public void Write<T>(Action<WritableBuffer, T> write, T state) public void Write<T>(Action<WritableBuffer, T> write, T state) where T : struct
{ {
} }

View File

@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Testing
ThreadPool = new LoggingThreadPool(Log); ThreadPool = new LoggingThreadPool(Log);
DateHeaderValueManager = new DateHeaderValueManager(systemClock: new MockSystemClock()); DateHeaderValueManager = new DateHeaderValueManager(systemClock: new MockSystemClock());
DateHeaderValue = DateHeaderValueManager.GetDateHeaderValues().String; DateHeaderValue = DateHeaderValueManager.GetDateHeaderValues().String;
HttpParserFactory = frame => new HttpParser(frame.ServiceContext.Log); HttpParserFactory = frameAdapter => new HttpParser<FrameAdapter>(frameAdapter.Frame.ServiceContext.Log);
ServerOptions = new KestrelServerOptions ServerOptions = new KestrelServerOptions
{ {
AddServerHeader = false AddServerHeader = false