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:
David Fowler 2017-03-01 13:12:03 -08:00 committed by GitHub
parent d3694f085a
commit cb6059c143
11 changed files with 49 additions and 17 deletions

View File

@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
ServerOptions = context.ListenerContext.ServiceContext.ServerOptions;
_pathBase = context.ListenerContext.ListenOptions.PathBase;
_parser = context.ListenerContext.ServiceContext.HttpParser;
_parser = context.ListenerContext.ServiceContext.HttpParserFactory(this);
FrameControl = this;
_keepAliveMilliseconds = (long)ServerOptions.Limits.KeepAliveTimeout.TotalMilliseconds;
@ -379,6 +379,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
_requestHeadersParsed = 0;
_responseBytesWritten = 0;
// When testing parser can be null
_parser.Reset();
}
/// <summary>

View File

@ -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 ParseHeaders<T>(T handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes) where T : IHttpHeadersHandler;
void Reset();
}
}

View File

@ -525,6 +525,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
Log.IsEnabled(LogLevel.Information) ? span.GetAsciiStringEscaped(MaxRequestLineError) : string.Empty);
}
public void Reset()
{
}
private enum HeaderState
{
Name,

View File

@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal
public IThreadPool ThreadPool { get; set; }
public IHttpParser HttpParser { get; set; }
public Func<Frame, IHttpParser> HttpParserFactory { get; set; }
public Func<ConnectionContext, Frame> FrameFactory { get; set; }

View File

@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
},
AppLifetime = _applicationLifetime,
Log = trace,
HttpParser = new KestrelHttpParser(trace),
HttpParserFactory = frame => new KestrelHttpParser(frame.ConnectionContext.ListenerContext.ServiceContext.Log),
ThreadPool = threadPool,
DateHeaderValueManager = dateHeaderValueManager,
ServerOptions = Options

View File

@ -162,7 +162,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
}
Pipe.Reader.Advance(consumed, examined);
}
while(true);
while (true);
}
private void ThrowInvalidStartLine()
@ -179,7 +179,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
public void Setup()
{
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);
PipelineFactory = new PipeFactory();

View File

@ -4,16 +4,14 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO.Pipelines;
using System.Net;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel;
using Microsoft.AspNetCore.Server.Kestrel.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.Extensions.Primitives;
using Xunit;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Server.KestrelTests
{
@ -27,7 +25,8 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
var serviceContext = new ServiceContext
{
DateHeaderValueManager = new DateHeaderValueManager(),
ServerOptions = serverOptions
ServerOptions = serverOptions,
HttpParserFactory = f => new NoopHttpParser(),
};
var listenerContext = new ListenerContext(serviceContext)
{
@ -268,5 +267,28 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
"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()
{
}
}
}
}

View File

@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
{
DateHeaderValueManager = new DateHeaderValueManager(),
ServerOptions = new KestrelServerOptions(),
HttpParser = new KestrelHttpParser(trace),
HttpParserFactory = frame => new KestrelHttpParser(trace),
Log = trace
};
var listenerContext = new ListenerContext(_serviceContext)
@ -484,7 +484,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
await _socketInput.Writer.WriteAsync(requestLineBytes);
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);
Assert.Equal("Request line too long.", exception.Message);

View File

@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
DateHeaderValueManager = serviceContextPrimary.DateHeaderValueManager,
ServerOptions = serviceContextPrimary.ServerOptions,
ThreadPool = serviceContextPrimary.ThreadPool,
HttpParser = new KestrelHttpParser(serviceContextPrimary.Log),
HttpParserFactory = frame => new KestrelHttpParser(serviceContextPrimary.Log),
FrameFactory = context =>
{
return new Frame<DefaultHttpContext>(new TestApplication(c =>
@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
DateHeaderValueManager = serviceContextPrimary.DateHeaderValueManager,
ServerOptions = serviceContextPrimary.ServerOptions,
ThreadPool = serviceContextPrimary.ThreadPool,
HttpParser = new KestrelHttpParser(serviceContextPrimary.Log),
HttpParserFactory = frame => new KestrelHttpParser(serviceContextPrimary.Log),
FrameFactory = context =>
{
return new Frame<DefaultHttpContext>(new TestApplication(c =>
@ -245,7 +245,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
DateHeaderValueManager = serviceContextPrimary.DateHeaderValueManager,
ServerOptions = serviceContextPrimary.ServerOptions,
ThreadPool = serviceContextPrimary.ThreadPool,
HttpParser = new KestrelHttpParser(serviceContextPrimary.Log),
HttpParserFactory = frame => new KestrelHttpParser(serviceContextPrimary.Log),
FrameFactory = context =>
{
return new Frame<DefaultHttpContext>(new TestApplication(c =>

View File

@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
{
DateHeaderValueManager = new DateHeaderValueManager(),
ServerOptions = new KestrelServerOptions(),
HttpParser = new KestrelHttpParser(trace),
HttpParserFactory = frame => new KestrelHttpParser(trace),
};
var listenerContext = new ListenerContext(serviceContext)
{
@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
_memoryPool = new MemoryPool();
_pipelineFactory = new PipeFactory();
FrameContext.Input = _pipelineFactory.Create();;
FrameContext.Input = _pipelineFactory.Create(); ;
}
public Frame FrameContext { get; set; }

View File

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