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:
parent
1faaefef30
commit
d29e4d4cf0
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue