Fixing a header parsing bug

When request header data arrives with \r\n split across packets
This commit is contained in:
Louis DeJardin 2015-09-16 21:50:13 -07:00
parent e5a3bda3a2
commit 52dc37eae7
15 changed files with 142 additions and 92 deletions

View File

@ -614,9 +614,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
chFirst = scan.Take(); // expecting: /r chFirst = scan.Take(); // expecting: /r
chSecond = scan.Take(); // expecting: /n chSecond = scan.Take(); // expecting: /n
if (chSecond == '\r') if (chSecond != '\n')
{ {
// special case, "\r\r". move to the 2nd "\r" and try again // "\r" was all by itself, move just after it and try again
scan = endValue; scan = endValue;
scan.Take(); scan.Take();
continue; continue;
@ -633,6 +633,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
} }
var name = beginName.GetArraySegment(endName); var name = beginName.GetArraySegment(endName);
#if DEBUG
var nameString = beginName.GetString(endName);
#endif
var value = beginValue.GetString(endValue); var value = beginValue.GetString(endValue);
if (wrapping) if (wrapping)
{ {

View File

@ -13,7 +13,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
/// </summary> /// </summary>
public abstract class Listener : ListenerContext, IDisposable public abstract class Listener : ListenerContext, IDisposable
{ {
protected Listener(ServiceContext serviceContext) : base(serviceContext) protected Listener(ServiceContext serviceContext)
: base(serviceContext)
{ {
Memory2 = new MemoryPool2(); Memory2 = new MemoryPool2();
} }

View File

@ -7,17 +7,19 @@ using Microsoft.AspNet.Server.Kestrel.Infrastructure;
namespace Microsoft.AspNet.Server.Kestrel.Http namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
public class ListenerContext public class ListenerContext : ServiceContext
{ {
public ListenerContext() { } public ListenerContext()
{
public ListenerContext(ServiceContext serviceContext) }
public ListenerContext(ServiceContext serviceContext)
: base(serviceContext)
{ {
Memory = serviceContext.Memory;
Log = serviceContext.Log;
} }
public ListenerContext(ListenerContext listenerContext) public ListenerContext(ListenerContext listenerContext)
: base(listenerContext)
{ {
Thread = listenerContext.Thread; Thread = listenerContext.Thread;
Application = listenerContext.Application; Application = listenerContext.Application;
@ -30,10 +32,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public Func<Frame, Task> Application { get; set; } public Func<Frame, Task> Application { get; set; }
public IMemoryPool Memory { get; set; }
public MemoryPool2 Memory2 { get; set; } public MemoryPool2 Memory2 { get; set; }
public IKestrelTrace Log { get; }
} }
} }

View File

@ -33,11 +33,11 @@ namespace Microsoft.AspNet.Server.Kestrel
private ExceptionDispatchInfo _closeError; private ExceptionDispatchInfo _closeError;
private IKestrelTrace _log; private IKestrelTrace _log;
public KestrelThread(KestrelEngine engine, ServiceContext serviceContext) public KestrelThread(KestrelEngine engine)
{ {
_engine = engine; _engine = engine;
_appShutdown = serviceContext.AppShutdown; _appShutdown = engine.AppShutdown;
_log = serviceContext.Log; _log = engine.Log;
_loop = new UvLoopHandle(_log); _loop = new UvLoopHandle(_log);
_post = new UvAsyncHandle(_log); _post = new UvAsyncHandle(_log);
_thread = new Thread(ThreadStart); _thread = new Thread(ThreadStart);

View File

@ -12,87 +12,87 @@ namespace Microsoft.AspNet.Server.Kestrel
/// </summary> /// </summary>
public class KestrelTrace : IKestrelTrace public class KestrelTrace : IKestrelTrace
{ {
private readonly ILogger _logger; protected readonly ILogger _logger;
public KestrelTrace(ILogger logger) public KestrelTrace(ILogger logger)
{ {
_logger = logger; _logger = logger;
} }
public void ConnectionStart(long connectionId) public virtual void ConnectionStart(long connectionId)
{ {
_logger.LogDebug(1, @"Connection id ""{ConnectionId}"" started.", connectionId); _logger.LogDebug(1, @"Connection id ""{ConnectionId}"" started.", connectionId);
} }
public void ConnectionStop(long connectionId) public virtual void ConnectionStop(long connectionId)
{ {
_logger.LogDebug(2, @"Connection id ""{ConnectionId}"" stopped.", connectionId); _logger.LogDebug(2, @"Connection id ""{ConnectionId}"" stopped.", connectionId);
} }
public void ConnectionRead(long connectionId, int count) public virtual void ConnectionRead(long connectionId, int count)
{ {
// Don't log for now since this could be *too* verbose. // Don't log for now since this could be *too* verbose.
// Reserved: Event ID 3 // Reserved: Event ID 3
} }
public void ConnectionPause(long connectionId) public virtual void ConnectionPause(long connectionId)
{ {
_logger.LogDebug(4, @"Connection id ""{ConnectionId}"" paused.", connectionId); _logger.LogDebug(4, @"Connection id ""{ConnectionId}"" paused.", connectionId);
} }
public void ConnectionResume(long connectionId) public virtual void ConnectionResume(long connectionId)
{ {
_logger.LogDebug(5, @"Connection id ""{ConnectionId}"" resumed.", connectionId); _logger.LogDebug(5, @"Connection id ""{ConnectionId}"" resumed.", connectionId);
} }
public void ConnectionReadFin(long connectionId) public virtual void ConnectionReadFin(long connectionId)
{ {
_logger.LogDebug(6, @"Connection id ""{ConnectionId}"" received FIN.", connectionId); _logger.LogDebug(6, @"Connection id ""{ConnectionId}"" received FIN.", connectionId);
} }
public void ConnectionWriteFin(long connectionId) public virtual void ConnectionWriteFin(long connectionId)
{ {
_logger.LogDebug(7, @"Connection id ""{ConnectionId}"" sending FIN.", connectionId); _logger.LogDebug(7, @"Connection id ""{ConnectionId}"" sending FIN.", connectionId);
} }
public void ConnectionWroteFin(long connectionId, int status) public virtual void ConnectionWroteFin(long connectionId, int status)
{ {
_logger.LogDebug(8, @"Connection id ""{ConnectionId}"" sent FIN with status ""{Status}"".", connectionId, status); _logger.LogDebug(8, @"Connection id ""{ConnectionId}"" sent FIN with status ""{Status}"".", connectionId, status);
} }
public void ConnectionKeepAlive(long connectionId) public virtual void ConnectionKeepAlive(long connectionId)
{ {
_logger.LogDebug(9, @"Connection id ""{ConnectionId}"" completed keep alive response.", connectionId); _logger.LogDebug(9, @"Connection id ""{ConnectionId}"" completed keep alive response.", connectionId);
} }
public void ConnectionDisconnect(long connectionId) public virtual void ConnectionDisconnect(long connectionId)
{ {
_logger.LogDebug(10, @"Connection id ""{ConnectionId}"" disconnected.", connectionId); _logger.LogDebug(10, @"Connection id ""{ConnectionId}"" disconnected.", connectionId);
} }
public void ConnectionWrite(long connectionId, int count) public virtual void ConnectionWrite(long connectionId, int count)
{ {
// Don't log for now since this could be *too* verbose. // Don't log for now since this could be *too* verbose.
// Reserved: Event ID 11 // Reserved: Event ID 11
} }
public void ConnectionWriteCallback(long connectionId, int status) public virtual void ConnectionWriteCallback(long connectionId, int status)
{ {
// Don't log for now since this could be *too* verbose. // Don't log for now since this could be *too* verbose.
// Reserved: Event ID 12 // Reserved: Event ID 12
} }
public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter) public virtual void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{ {
_logger.Log(logLevel, eventId, state, exception, formatter); _logger.Log(logLevel, eventId, state, exception, formatter);
} }
public bool IsEnabled(LogLevel logLevel) public virtual bool IsEnabled(LogLevel logLevel)
{ {
return _logger.IsEnabled(logLevel); return _logger.IsEnabled(logLevel);
} }
public IDisposable BeginScopeImpl(object state) public virtual IDisposable BeginScopeImpl(object state)
{ {
return _logger.BeginScopeImpl(state); return _logger.BeginScopeImpl(state);
} }

View File

@ -13,12 +13,10 @@ using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Server.Kestrel namespace Microsoft.AspNet.Server.Kestrel
{ {
public class KestrelEngine : IDisposable public class KestrelEngine : ServiceContext, IDisposable
{ {
private readonly ServiceContext _serviceContext; public KestrelEngine(ILibraryManager libraryManager, ServiceContext context)
: this(context)
public KestrelEngine(ILibraryManager libraryManager, IApplicationShutdown appShutdownService, ILogger logger)
: this(appShutdownService, logger)
{ {
Libuv = new Libuv(); Libuv = new Libuv();
@ -63,21 +61,15 @@ namespace Microsoft.AspNet.Server.Kestrel
} }
// For testing // For testing
internal KestrelEngine(Libuv uv, IApplicationShutdown appShutdownService, ILogger logger) internal KestrelEngine(Libuv uv, ServiceContext context)
: this(appShutdownService, logger) : this(context)
{ {
Libuv = uv; Libuv = uv;
} }
private KestrelEngine(IApplicationShutdown appShutdownService, ILogger logger) private KestrelEngine(ServiceContext context)
: base(context)
{ {
_serviceContext = new ServiceContext
{
AppShutdown = appShutdownService,
Memory = new MemoryPool(),
Log = new KestrelTrace(logger)
};
Threads = new List<KestrelThread>(); Threads = new List<KestrelThread>();
} }
@ -88,7 +80,7 @@ namespace Microsoft.AspNet.Server.Kestrel
{ {
for (var index = 0; index != count; ++index) for (var index = 0; index != count; ++index)
{ {
Threads.Add(new KestrelThread(this, _serviceContext)); Threads.Add(new KestrelThread(this));
} }
foreach (var thread in Threads) foreach (var thread in Threads)
@ -128,16 +120,16 @@ namespace Microsoft.AspNet.Server.Kestrel
if (single) if (single)
{ {
var listener = usingPipes ? var listener = usingPipes ?
(Listener) new PipeListener(_serviceContext) : (Listener) new PipeListener(this) :
new TcpListener(_serviceContext); new TcpListener(this);
listeners.Add(listener); listeners.Add(listener);
listener.StartAsync(scheme, host, port, thread, application).Wait(); listener.StartAsync(scheme, host, port, thread, application).Wait();
} }
else if (first) else if (first)
{ {
var listener = usingPipes var listener = usingPipes
? (ListenerPrimary) new PipeListenerPrimary(_serviceContext) ? (ListenerPrimary) new PipeListenerPrimary(this)
: new TcpListenerPrimary(_serviceContext); : new TcpListenerPrimary(this);
listeners.Add(listener); listeners.Add(listener);
listener.StartAsync(pipeName, scheme, host, port, thread, application).Wait(); listener.StartAsync(pipeName, scheme, host, port, thread, application).Wait();
@ -145,8 +137,8 @@ namespace Microsoft.AspNet.Server.Kestrel
else else
{ {
var listener = usingPipes var listener = usingPipes
? (ListenerSecondary) new PipeListenerSecondary(_serviceContext) ? (ListenerSecondary) new PipeListenerSecondary(this)
: new TcpListenerSecondary(_serviceContext); : new TcpListenerSecondary(this);
listeners.Add(listener); listeners.Add(listener);
listener.StartAsync(pipeName, thread, application).Wait(); listener.StartAsync(pipeName, thread, application).Wait();
} }

View File

@ -53,14 +53,14 @@ namespace Microsoft.AspNet.Server.Kestrel
try try
{ {
var information = (KestrelServerInformation)serverFeatures.Get<IKestrelServerInformation>(); var information = (KestrelServerInformation)serverFeatures.Get<IKestrelServerInformation>();
var engine = new KestrelEngine(_libraryManager, _appShutdownService, _logger); var engine = new KestrelEngine(_libraryManager, new ServiceContext { AppShutdown = _appShutdownService, Log = new KestrelTrace(_logger) });
disposables.Push(engine); disposables.Push(engine);
if (information.ThreadCount < 0) if (information.ThreadCount < 0)
{ {
throw new ArgumentOutOfRangeException(nameof(information.ThreadCount), throw new ArgumentOutOfRangeException(nameof(information.ThreadCount),
information.ThreadCount, information.ThreadCount,
"ThreadCount cannot be negative"); "ThreadCount cannot be negative");
} }

View File

@ -9,6 +9,18 @@ namespace Microsoft.AspNet.Server.Kestrel
{ {
public class ServiceContext public class ServiceContext
{ {
public ServiceContext()
{
Memory = new MemoryPool();
}
public ServiceContext(ServiceContext context)
{
AppShutdown = context.AppShutdown;
Memory = context.Memory;
Log = context.Log;
}
public IApplicationShutdown AppShutdown { get; set; } public IApplicationShutdown AppShutdown { get; set; }
public IMemoryPool Memory { get; set; } public IMemoryPool Memory { get; set; }

View File

@ -61,19 +61,20 @@ namespace Microsoft.AspNet.Server.KestrelTests
private async Task AppChunked(Frame frame) private async Task AppChunked(Frame frame)
{ {
Console.WriteLine($"----");
Console.WriteLine($"{frame.Method} {frame.RequestUri} {frame.HttpVersion}");
foreach (var h in frame.RequestHeaders) foreach (var h in frame.RequestHeaders)
{ {
Console.WriteLine($"{h.Key}: {h.Value}"); Console.WriteLine($"{h.Key}: {h.Value}");
} }
Console.WriteLine($""); Console.WriteLine($"");
frame.ResponseHeaders.Clear();
var data = new MemoryStream(); var data = new MemoryStream();
while(true) await frame.RequestBody.CopyToAsync(data);
{
await frame.RequestBody.CopyToAsync(data);
}
var bytes = data.ToArray(); var bytes = data.ToArray();
Console.WriteLine($"{Encoding.ASCII.GetString(bytes)}");
frame.ResponseHeaders.Clear();
frame.ResponseHeaders["Content-Length"] = new[] { bytes.Length.ToString() }; frame.ResponseHeaders["Content-Length"] = new[] { bytes.Length.ToString() };
await frame.ResponseBody.WriteAsync(bytes, 0, bytes.Length); await frame.ResponseBody.WriteAsync(bytes, 0, bytes.Length);
} }
@ -87,7 +88,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void EngineCanStartAndStop() public void EngineCanStartAndStop()
{ {
var engine = new KestrelEngine(LibraryManager, new ShutdownNotImplemented(), new TestLogger()); var engine = new KestrelEngine(LibraryManager, new TestServiceContext());
engine.Start(1); engine.Start(1);
engine.Dispose(); engine.Dispose();
} }
@ -95,7 +96,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void ListenerCanCreateAndDispose() public void ListenerCanCreateAndDispose()
{ {
var engine = new KestrelEngine(LibraryManager, new ShutdownNotImplemented(), new TestLogger()); var engine = new KestrelEngine(LibraryManager, new TestServiceContext());
engine.Start(1); engine.Start(1);
var started = engine.CreateServer("http", "localhost", 54321, App); var started = engine.CreateServer("http", "localhost", 54321, App);
started.Dispose(); started.Dispose();
@ -106,7 +107,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void ConnectionCanReadAndWrite() public void ConnectionCanReadAndWrite()
{ {
var engine = new KestrelEngine(LibraryManager, new ShutdownNotImplemented(), new TestLogger()); var engine = new KestrelEngine(LibraryManager, new TestServiceContext());
engine.Start(1); engine.Start(1);
var started = engine.CreateServer("http", "localhost", 54321, App); var started = engine.CreateServer("http", "localhost", 54321, App);

View File

@ -15,11 +15,12 @@ namespace Microsoft.AspNet.Server.KestrelTests
public class MultipleLoopTests public class MultipleLoopTests
{ {
private readonly Libuv _uv; private readonly Libuv _uv;
private readonly IKestrelTrace _logger = new KestrelTrace(new TestLogger()); private readonly IKestrelTrace _logger;
public MultipleLoopTests() public MultipleLoopTests()
{ {
var engine = new KestrelEngine(LibraryManager, new ShutdownNotImplemented(), new TestLogger()); var engine = new KestrelEngine(LibraryManager, new TestServiceContext());
_uv = engine.Libuv; _uv = engine.Libuv;
_logger = engine.Log;
} }
ILibraryManager LibraryManager ILibraryManager LibraryManager
@ -81,7 +82,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
return; return;
} }
var writeRequest = new UvWriteReq(new KestrelTrace(new TestLogger())); var writeRequest = new UvWriteReq(new KestrelTrace(new TestKestrelTrace()));
writeRequest.Init(loop); writeRequest.Init(loop);
writeRequest.Write( writeRequest.Write(
serverConnectionPipe, serverConnectionPipe,
@ -100,7 +101,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
{ {
var loop2 = new UvLoopHandle(_logger); var loop2 = new UvLoopHandle(_logger);
var clientConnectionPipe = new UvPipeHandle(_logger); var clientConnectionPipe = new UvPipeHandle(_logger);
var connect = new UvConnectRequest(new KestrelTrace(new TestLogger())); var connect = new UvConnectRequest(new KestrelTrace(new TestKestrelTrace()));
loop2.Init(_uv); loop2.Init(_uv);
clientConnectionPipe.Init(loop2, true); clientConnectionPipe.Init(loop2, true);
@ -174,7 +175,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
serverConnectionPipeAcceptedEvent.WaitOne(); serverConnectionPipeAcceptedEvent.WaitOne();
var writeRequest = new UvWriteReq(new KestrelTrace(new TestLogger())); var writeRequest = new UvWriteReq(new KestrelTrace(new TestKestrelTrace()));
writeRequest.Init(loop); writeRequest.Init(loop);
writeRequest.Write2( writeRequest.Write2(
serverConnectionPipe, serverConnectionPipe,
@ -196,7 +197,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
{ {
var loop2 = new UvLoopHandle(_logger); var loop2 = new UvLoopHandle(_logger);
var clientConnectionPipe = new UvPipeHandle(_logger); var clientConnectionPipe = new UvPipeHandle(_logger);
var connect = new UvConnectRequest(new KestrelTrace(new TestLogger())); var connect = new UvConnectRequest(new KestrelTrace(new TestKestrelTrace()));
loop2.Init(_uv); loop2.Init(_uv);
clientConnectionPipe.Init(loop2, true); clientConnectionPipe.Init(loop2, true);

View File

@ -21,11 +21,12 @@ namespace Microsoft.AspNet.Server.KestrelTests
public class NetworkingTests public class NetworkingTests
{ {
private readonly Libuv _uv; private readonly Libuv _uv;
private readonly IKestrelTrace _logger = new KestrelTrace(new TestLogger()); private readonly IKestrelTrace _logger;
public NetworkingTests() public NetworkingTests()
{ {
var engine = new KestrelEngine(LibraryManager, new ShutdownNotImplemented(), new TestLogger()); var engine = new KestrelEngine(LibraryManager, new TestServiceContext());
_uv = engine.Libuv; _uv = engine.Libuv;
_logger = engine.Log;
} }
ILibraryManager LibraryManager ILibraryManager LibraryManager
@ -208,7 +209,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
{ {
for (var x = 0; x != 2; ++x) for (var x = 0; x != 2; ++x)
{ {
var req = new UvWriteReq(new KestrelTrace(new TestLogger())); var req = new UvWriteReq(new KestrelTrace(new TestKestrelTrace()));
req.Init(loop); req.Init(loop);
req.Write( req.Write(
tcp2, tcp2,

View File

@ -32,13 +32,13 @@ namespace Microsoft.AspNet.Server.KestrelTests
} }
}; };
using (var kestrelEngine = new KestrelEngine(mockLibuv, new ShutdownNotImplemented(), new TestLogger())) using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
{ {
kestrelEngine.Start(count: 1); kestrelEngine.Start(count: 1);
var kestrelThread = kestrelEngine.Threads[0]; var kestrelThread = kestrelEngine.Threads[0];
var socket = new MockSocket(kestrelThread.Loop.ThreadId, new KestrelTrace(new TestLogger())); var socket = new MockSocket(kestrelThread.Loop.ThreadId, new KestrelTrace(new TestKestrelTrace()));
var trace = new KestrelTrace(new TestLogger()); var trace = new KestrelTrace(new TestKestrelTrace());
var socketOutput = new SocketOutput(kestrelThread, socket, 0, trace); var socketOutput = new SocketOutput(kestrelThread, socket, 0, trace);
// I doubt _maxBytesPreCompleted will ever be over a MB. If it is, we should change this test. // I doubt _maxBytesPreCompleted will ever be over a MB. If it is, we should change this test.
@ -77,13 +77,13 @@ namespace Microsoft.AspNet.Server.KestrelTests
} }
}; };
using (var kestrelEngine = new KestrelEngine(mockLibuv, new ShutdownNotImplemented(), new TestLogger())) using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
{ {
kestrelEngine.Start(count: 1); kestrelEngine.Start(count: 1);
var kestrelThread = kestrelEngine.Threads[0]; var kestrelThread = kestrelEngine.Threads[0];
var socket = new MockSocket(kestrelThread.Loop.ThreadId, new KestrelTrace(new TestLogger())); var socket = new MockSocket(kestrelThread.Loop.ThreadId, new KestrelTrace(new TestKestrelTrace()));
var trace = new KestrelTrace(new TestLogger()); var trace = new KestrelTrace(new TestKestrelTrace());
var socketOutput = new SocketOutput(kestrelThread, socket, 0, trace); var socketOutput = new SocketOutput(kestrelThread, socket, 0, trace);
var bufferSize = maxBytesPreCompleted; var bufferSize = maxBytesPreCompleted;

View File

@ -4,20 +4,44 @@ using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Server.KestrelTests namespace Microsoft.AspNet.Server.KestrelTests
{ {
public class TestLogger : ILogger public class TestKestrelTrace : KestrelTrace
{ {
public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter) public TestKestrelTrace() : base(new TestLogger())
{ {
} }
public bool IsEnabled(LogLevel logLevel) public override void ConnectionRead(long connectionId, int count)
{ {
return false; _logger.LogDebug(1, @"Connection id ""{ConnectionId}"" recv {count} bytes.", connectionId, count);
} }
public IDisposable BeginScopeImpl(object state) public override void ConnectionWrite(long connectionId, int count)
{ {
return new Disposable(() => { }); _logger.LogDebug(1, @"Connection id ""{ConnectionId}"" send {count} bytes.", connectionId, count);
}
public override void ConnectionWriteCallback(long connectionId, int status)
{
_logger.LogDebug(1, @"Connection id ""{ConnectionId}"" send finished with status {status}.", connectionId, status);
}
public class TestLogger : ILogger
{
public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
Console.WriteLine($"Log {logLevel}[{eventId}]: {formatter(state, exception)} {exception?.Message}");
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public IDisposable BeginScopeImpl(object state)
{
return new Disposable(() => { });
}
} }
} }
} }

View File

@ -27,25 +27,29 @@ namespace Microsoft.AspNet.Server.KestrelTests
{ {
get get
{ {
try{ try
{
var locator = CallContextServiceLocator.Locator; var locator = CallContextServiceLocator.Locator;
if (locator == null) if (locator == null)
{ {
return null; return null;
} }
var services = locator.ServiceProvider; var services = locator.ServiceProvider;
if (services == null) if (services == null)
{ {
return null; return null;
} }
return (ILibraryManager)services.GetService(typeof(ILibraryManager)); return (ILibraryManager)services.GetService(typeof(ILibraryManager));
} catch (NullReferenceException) { return null; } }
catch (NullReferenceException) { return null; }
} }
} }
public void Create(Func<Frame, Task> app) public void Create(Func<Frame, Task> app)
{ {
_engine = new KestrelEngine(LibraryManager, new ShutdownNotImplemented(), new TestLogger()); _engine = new KestrelEngine(
LibraryManager,
new TestServiceContext());
_engine.Start(1); _engine.Start(1);
_server = _engine.CreateServer( _server = _engine.CreateServer(
"http", "http",

View File

@ -0,0 +1,13 @@
using Microsoft.AspNet.Server.Kestrel;
namespace Microsoft.AspNet.Server.KestrelTests
{
public class TestServiceContext : ServiceContext
{
public TestServiceContext()
{
AppShutdown = new ShutdownNotImplemented();
Log = new TestKestrelTrace();
}
}
}