Make the IHttpParser per frame and add a reset (#1415)
* Make the IHttpParser per frame and add a reset - Made the IHttpParser a per frame object so state can be stored across method calls and parses. - Added HttpParserFactory to ServiceContext
This commit is contained in:
parent
d3694f085a
commit
cb6059c143
|
|
@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
ServerOptions = context.ListenerContext.ServiceContext.ServerOptions;
|
ServerOptions = context.ListenerContext.ServiceContext.ServerOptions;
|
||||||
|
|
||||||
_pathBase = context.ListenerContext.ListenOptions.PathBase;
|
_pathBase = context.ListenerContext.ListenOptions.PathBase;
|
||||||
_parser = context.ListenerContext.ServiceContext.HttpParser;
|
_parser = context.ListenerContext.ServiceContext.HttpParserFactory(this);
|
||||||
|
|
||||||
FrameControl = this;
|
FrameControl = this;
|
||||||
_keepAliveMilliseconds = (long)ServerOptions.Limits.KeepAliveTimeout.TotalMilliseconds;
|
_keepAliveMilliseconds = (long)ServerOptions.Limits.KeepAliveTimeout.TotalMilliseconds;
|
||||||
|
|
@ -379,6 +379,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
_requestHeadersParsed = 0;
|
_requestHeadersParsed = 0;
|
||||||
|
|
||||||
_responseBytesWritten = 0;
|
_responseBytesWritten = 0;
|
||||||
|
|
||||||
|
// When testing parser can be null
|
||||||
|
_parser.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
bool ParseRequestLine<T>(T handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) where T : IHttpRequestLineHandler;
|
bool ParseRequestLine<T>(T handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) where T : IHttpRequestLineHandler;
|
||||||
|
|
||||||
bool ParseHeaders<T>(T handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes) where T : IHttpHeadersHandler;
|
bool ParseHeaders<T>(T handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes) where T : IHttpHeadersHandler;
|
||||||
|
|
||||||
|
void Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -525,6 +525,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
Log.IsEnabled(LogLevel.Information) ? span.GetAsciiStringEscaped(MaxRequestLineError) : string.Empty);
|
Log.IsEnabled(LogLevel.Information) ? span.GetAsciiStringEscaped(MaxRequestLineError) : string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private enum HeaderState
|
private enum HeaderState
|
||||||
{
|
{
|
||||||
Name,
|
Name,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal
|
||||||
|
|
||||||
public IThreadPool ThreadPool { get; set; }
|
public IThreadPool ThreadPool { get; set; }
|
||||||
|
|
||||||
public IHttpParser HttpParser { get; set; }
|
public Func<Frame, IHttpParser> HttpParserFactory { get; set; }
|
||||||
|
|
||||||
public Func<ConnectionContext, Frame> FrameFactory { get; set; }
|
public Func<ConnectionContext, Frame> FrameFactory { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
||||||
},
|
},
|
||||||
AppLifetime = _applicationLifetime,
|
AppLifetime = _applicationLifetime,
|
||||||
Log = trace,
|
Log = trace,
|
||||||
HttpParser = new KestrelHttpParser(trace),
|
HttpParserFactory = frame => new KestrelHttpParser(frame.ConnectionContext.ListenerContext.ServiceContext.Log),
|
||||||
ThreadPool = threadPool,
|
ThreadPool = threadPool,
|
||||||
DateHeaderValueManager = dateHeaderValueManager,
|
DateHeaderValueManager = dateHeaderValueManager,
|
||||||
ServerOptions = Options
|
ServerOptions = Options
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
}
|
}
|
||||||
Pipe.Reader.Advance(consumed, examined);
|
Pipe.Reader.Advance(consumed, examined);
|
||||||
}
|
}
|
||||||
while(true);
|
while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThrowInvalidStartLine()
|
private void ThrowInvalidStartLine()
|
||||||
|
|
@ -179,7 +179,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
var connectionContext = new MockConnection(new KestrelServerOptions());
|
var connectionContext = new MockConnection(new KestrelServerOptions());
|
||||||
connectionContext.ListenerContext.ServiceContext.HttpParser = (IHttpParser) Activator.CreateInstance(ParserType, connectionContext.ListenerContext.ServiceContext.Log);
|
connectionContext.ListenerContext.ServiceContext.HttpParserFactory = frame => (IHttpParser)Activator.CreateInstance(ParserType, frame.ConnectionContext.ListenerContext.ServiceContext.Log);
|
||||||
|
|
||||||
Frame = new Frame<object>(application: null, context: connectionContext);
|
Frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
PipelineFactory = new PipeFactory();
|
PipelineFactory = new PipeFactory();
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,14 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.IO.Pipelines;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel;
|
using Microsoft.AspNetCore.Server.Kestrel;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Internal;
|
using Microsoft.AspNetCore.Server.Kestrel.Internal;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
|
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
|
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Microsoft.Net.Http.Headers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.KestrelTests
|
namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
|
|
@ -27,7 +25,8 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
var serviceContext = new ServiceContext
|
var serviceContext = new ServiceContext
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerOptions = serverOptions
|
ServerOptions = serverOptions,
|
||||||
|
HttpParserFactory = f => new NoopHttpParser(),
|
||||||
};
|
};
|
||||||
var listenerContext = new ListenerContext(serviceContext)
|
var listenerContext = new ListenerContext(serviceContext)
|
||||||
{
|
{
|
||||||
|
|
@ -268,5 +267,28 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
"42,000",
|
"42,000",
|
||||||
"42.000",
|
"42.000",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private class NoopHttpParser : IHttpParser
|
||||||
|
{
|
||||||
|
public bool ParseHeaders<T>(T handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes) where T : IHttpHeadersHandler
|
||||||
|
{
|
||||||
|
consumed = buffer.Start;
|
||||||
|
examined = buffer.End;
|
||||||
|
consumedBytes = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ParseRequestLine<T>(T handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) where T : IHttpRequestLineHandler
|
||||||
|
{
|
||||||
|
consumed = buffer.Start;
|
||||||
|
examined = buffer.End;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerOptions = new KestrelServerOptions(),
|
ServerOptions = new KestrelServerOptions(),
|
||||||
HttpParser = new KestrelHttpParser(trace),
|
HttpParserFactory = frame => new KestrelHttpParser(trace),
|
||||||
Log = trace
|
Log = trace
|
||||||
};
|
};
|
||||||
var listenerContext = new ListenerContext(_serviceContext)
|
var listenerContext = new ListenerContext(_serviceContext)
|
||||||
|
|
@ -484,7 +484,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
await _socketInput.Writer.WriteAsync(requestLineBytes);
|
await _socketInput.Writer.WriteAsync(requestLineBytes);
|
||||||
|
|
||||||
var readableBuffer = (await _socketInput.Reader.ReadAsync()).Buffer;
|
var readableBuffer = (await _socketInput.Reader.ReadAsync()).Buffer;
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>_frame.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
var exception = Assert.Throws<BadHttpRequestException>(() => _frame.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
||||||
_socketInput.Reader.Advance(_consumed, _examined);
|
_socketInput.Reader.Advance(_consumed, _examined);
|
||||||
|
|
||||||
Assert.Equal("Request line too long.", exception.Message);
|
Assert.Equal("Request line too long.", exception.Message);
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
DateHeaderValueManager = serviceContextPrimary.DateHeaderValueManager,
|
DateHeaderValueManager = serviceContextPrimary.DateHeaderValueManager,
|
||||||
ServerOptions = serviceContextPrimary.ServerOptions,
|
ServerOptions = serviceContextPrimary.ServerOptions,
|
||||||
ThreadPool = serviceContextPrimary.ThreadPool,
|
ThreadPool = serviceContextPrimary.ThreadPool,
|
||||||
HttpParser = new KestrelHttpParser(serviceContextPrimary.Log),
|
HttpParserFactory = frame => new KestrelHttpParser(serviceContextPrimary.Log),
|
||||||
FrameFactory = context =>
|
FrameFactory = context =>
|
||||||
{
|
{
|
||||||
return new Frame<DefaultHttpContext>(new TestApplication(c =>
|
return new Frame<DefaultHttpContext>(new TestApplication(c =>
|
||||||
|
|
@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
DateHeaderValueManager = serviceContextPrimary.DateHeaderValueManager,
|
DateHeaderValueManager = serviceContextPrimary.DateHeaderValueManager,
|
||||||
ServerOptions = serviceContextPrimary.ServerOptions,
|
ServerOptions = serviceContextPrimary.ServerOptions,
|
||||||
ThreadPool = serviceContextPrimary.ThreadPool,
|
ThreadPool = serviceContextPrimary.ThreadPool,
|
||||||
HttpParser = new KestrelHttpParser(serviceContextPrimary.Log),
|
HttpParserFactory = frame => new KestrelHttpParser(serviceContextPrimary.Log),
|
||||||
FrameFactory = context =>
|
FrameFactory = context =>
|
||||||
{
|
{
|
||||||
return new Frame<DefaultHttpContext>(new TestApplication(c =>
|
return new Frame<DefaultHttpContext>(new TestApplication(c =>
|
||||||
|
|
@ -245,7 +245,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
DateHeaderValueManager = serviceContextPrimary.DateHeaderValueManager,
|
DateHeaderValueManager = serviceContextPrimary.DateHeaderValueManager,
|
||||||
ServerOptions = serviceContextPrimary.ServerOptions,
|
ServerOptions = serviceContextPrimary.ServerOptions,
|
||||||
ThreadPool = serviceContextPrimary.ThreadPool,
|
ThreadPool = serviceContextPrimary.ThreadPool,
|
||||||
HttpParser = new KestrelHttpParser(serviceContextPrimary.Log),
|
HttpParserFactory = frame => new KestrelHttpParser(serviceContextPrimary.Log),
|
||||||
FrameFactory = context =>
|
FrameFactory = context =>
|
||||||
{
|
{
|
||||||
return new Frame<DefaultHttpContext>(new TestApplication(c =>
|
return new Frame<DefaultHttpContext>(new TestApplication(c =>
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerOptions = new KestrelServerOptions(),
|
ServerOptions = new KestrelServerOptions(),
|
||||||
HttpParser = new KestrelHttpParser(trace),
|
HttpParserFactory = frame => new KestrelHttpParser(trace),
|
||||||
};
|
};
|
||||||
var listenerContext = new ListenerContext(serviceContext)
|
var listenerContext = new ListenerContext(serviceContext)
|
||||||
{
|
{
|
||||||
|
|
@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
|
|
||||||
_memoryPool = new MemoryPool();
|
_memoryPool = new MemoryPool();
|
||||||
_pipelineFactory = new PipeFactory();
|
_pipelineFactory = new PipeFactory();
|
||||||
FrameContext.Input = _pipelineFactory.Create();;
|
FrameContext.Input = _pipelineFactory.Create(); ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Frame FrameContext { get; set; }
|
public Frame FrameContext { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,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;
|
||||||
HttpParser = new KestrelHttpParser(Log);
|
HttpParserFactory = frame => new KestrelHttpParser(Log);
|
||||||
ServerOptions = new KestrelServerOptions
|
ServerOptions = new KestrelServerOptions
|
||||||
{
|
{
|
||||||
AddServerHeader = false,
|
AddServerHeader = false,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue