Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

Reacting to Hosting changes #307

Merged
merged 1 commit into from
Oct 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,10 @@ public async Task RequestProcessingAsync()
ResponseBody = new FrameResponseStream(this);
DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody);

var httpContext = HttpContextFactory.Create(this);
try
{
await Application.Invoke(this).ConfigureAwait(false);
await Application.Invoke(httpContext).ConfigureAwait(false);
}
catch (Exception ex)
{
Expand All @@ -227,6 +228,8 @@ public async Task RequestProcessingAsync()

await FireOnCompleted();

HttpContextFactory.Dispose(httpContext);

await ProduceEnd();

while (await RequestBody.ReadAsync(_nullBuffer, 0, _nullBuffer.Length) != 0)
Expand Down
3 changes: 2 additions & 1 deletion src/Microsoft.AspNet.Server.Kestrel/Http/Listener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Server.Kestrel.Networking;
using Microsoft.Extensions.Logging;

Expand All @@ -23,7 +24,7 @@ protected Listener(ServiceContext serviceContext)
public Task StartAsync(
ServerAddress address,
KestrelThread thread,
Func<Frame, Task> application)
RequestDelegate application)
{
ServerAddress = address;
Thread = thread;
Expand Down
5 changes: 2 additions & 3 deletions src/Microsoft.AspNet.Server.Kestrel/Http/ListenerContext.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// 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 System;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Server.Kestrel.Infrastructure;

namespace Microsoft.AspNet.Server.Kestrel.Http
Expand Down Expand Up @@ -34,7 +33,7 @@ public ListenerContext(ListenerContext listenerContext)

public KestrelThread Thread { get; set; }

public Func<Frame, Task> Application { get; set; }
public RequestDelegate Application { get; set; }

public MemoryPool2 Memory2 { get; set; }
}
Expand Down
3 changes: 2 additions & 1 deletion src/Microsoft.AspNet.Server.Kestrel/Http/ListenerPrimary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
using Microsoft.AspNet.Server.Kestrel.Networking;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -33,7 +34,7 @@ public async Task StartAsync(
string pipeName,
ServerAddress address,
KestrelThread thread,
Func<Frame, Task> application)
RequestDelegate application)
{
await StartAsync(address, thread, application).ConfigureAwait(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
using Microsoft.AspNet.Server.Kestrel.Networking;
using Microsoft.Extensions.Logging;
Expand All @@ -26,7 +27,7 @@ public Task StartAsync(
string pipeName,
ServerAddress address,
KestrelThread thread,
Func<Frame, Task> application)
RequestDelegate application)
{
ServerAddress = address;
Thread = thread;
Expand Down
5 changes: 2 additions & 3 deletions src/Microsoft.AspNet.Server.Kestrel/KestrelEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.AspNet.Server.Kestrel.Networking;

Expand Down Expand Up @@ -49,7 +48,7 @@ public void Dispose()
Threads.Clear();
}

public IDisposable CreateServer(ServerAddress address, Func<IFeatureCollection, Task> application)
public IDisposable CreateServer(ServerAddress address, RequestDelegate application)
{
var listeners = new List<IDisposable>();

Expand Down
128 changes: 128 additions & 0 deletions src/Microsoft.AspNet.Server.Kestrel/KestrelServer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// 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 System;
using System.Collections.Generic;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.Extensions.Logging;

namespace Microsoft.AspNet.Server.Kestrel
{
public class KestrelServer : IServer
{
private Stack<IDisposable> _disposables;
private readonly IApplicationLifetime _applicationLifetime;
private readonly ILogger _logger;
private readonly IHttpContextFactory _httpContextFactory;

public KestrelServer(IFeatureCollection features, IApplicationLifetime applicationLifetime, ILogger logger, IHttpContextFactory httpContextFactory)
{
if (features == null)
{
throw new ArgumentNullException(nameof(features));
}

if (applicationLifetime == null)
{
throw new ArgumentNullException(nameof(applicationLifetime));
}

if (logger == null)
{
throw new ArgumentNullException(nameof(logger));
}

if (httpContextFactory == null)
{
throw new ArgumentNullException(nameof(httpContextFactory));
}

_applicationLifetime = applicationLifetime;
_logger = logger;
Features = features;
_httpContextFactory = httpContextFactory;
}

public IFeatureCollection Features { get; }

public void Start(RequestDelegate requestDelegate)
{
if (_disposables != null)
{
// The server has already started and/or has not been cleaned up yet
throw new InvalidOperationException("Server has already started.");
}
_disposables = new Stack<IDisposable>();

try
{
var information = (KestrelServerInformation)Features.Get<IKestrelServerInformation>();
var dateHeaderValueManager = new DateHeaderValueManager();
var engine = new KestrelEngine(new ServiceContext
{
AppLifetime = _applicationLifetime,
Log = new KestrelTrace(_logger),
HttpContextFactory = _httpContextFactory,
DateHeaderValueManager = dateHeaderValueManager,
ConnectionFilter = information.ConnectionFilter,
NoDelay = information.NoDelay
});

_disposables.Push(engine);
_disposables.Push(dateHeaderValueManager);

if (information.ThreadCount < 0)
{
throw new ArgumentOutOfRangeException(nameof(information.ThreadCount),
information.ThreadCount,
"ThreadCount cannot be negative");
}

engine.Start(information.ThreadCount == 0 ? 1 : information.ThreadCount);
var atLeastOneListener = false;

foreach (var address in information.Addresses)
{
var parsedAddress = ServerAddress.FromUrl(address);
if (parsedAddress == null)
{
throw new FormatException("Unrecognized listening address: " + address);
}
else
{
atLeastOneListener = true;
_disposables.Push(engine.CreateServer(
parsedAddress,
requestDelegate));
}
}

if (!atLeastOneListener)
{
throw new InvalidOperationException("No recognized listening addresses were configured.");
}
}
catch
{
Dispose();
throw;
}
}

public void Dispose()
{
if (_disposables != null)
{
while (_disposables.Count > 0)
{
_disposables.Pop().Dispose();
}
_disposables = null;
}
}
}
}
84 changes: 8 additions & 76 deletions src/Microsoft.AspNet.Server.Kestrel/ServerFactory.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
// 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 System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Features;
using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

Expand All @@ -20,89 +17,24 @@ namespace Microsoft.AspNet.Server.Kestrel
public class ServerFactory : IServerFactory
{
private readonly IApplicationLifetime _appLifetime;
private readonly ILogger _logger;
private readonly ILoggerFactory _loggerFactory;
private readonly IHttpContextFactory _httpContextFactory;

public ServerFactory(IApplicationLifetime appLifetime, ILoggerFactory loggerFactory)
public ServerFactory(IApplicationLifetime appLifetime, ILoggerFactory loggerFactory, IHttpContextFactory httpContextFactory)
{
_appLifetime = appLifetime;
_logger = loggerFactory.CreateLogger("Microsoft.AspNet.Server.Kestrel");
_loggerFactory = loggerFactory;
_httpContextFactory = httpContextFactory;
}

public IFeatureCollection Initialize(IConfiguration configuration)
public IServer CreateServer(IConfiguration configuration)
{
var information = new KestrelServerInformation();
information.Initialize(configuration);
var serverFeatures = new FeatureCollection();
serverFeatures.Set<IKestrelServerInformation>(information);
serverFeatures.Set<IServerAddressesFeature>(information);
return serverFeatures;
}

public IDisposable Start(IFeatureCollection serverFeatures, Func<IFeatureCollection, Task> application)
{
var disposables = new Stack<IDisposable>();
var disposer = new Disposable(() =>
{
foreach (var disposable in disposables)
{
disposable.Dispose();
}
});

try
{
var information = (KestrelServerInformation)serverFeatures.Get<IKestrelServerInformation>();
var dateHeaderValueManager = new DateHeaderValueManager();
var engine = new KestrelEngine(new ServiceContext
{
AppLifetime = _appLifetime,
Log = new KestrelTrace(_logger),
DateHeaderValueManager = dateHeaderValueManager,
ConnectionFilter = information.ConnectionFilter,
NoDelay = information.NoDelay
});

disposables.Push(engine);
disposables.Push(dateHeaderValueManager);

if (information.ThreadCount < 0)
{
throw new ArgumentOutOfRangeException(nameof(information.ThreadCount),
information.ThreadCount,
"ThreadCount cannot be negative");
}

engine.Start(information.ThreadCount == 0 ? 1 : information.ThreadCount);
bool atLeastOneListener = false;

foreach (var address in information.Addresses)
{
var parsedAddress = ServerAddress.FromUrl(address);
if (parsedAddress == null)
{
throw new FormatException("Unrecognized listening address: " + address);
}
else
{
atLeastOneListener = true;
disposables.Push(engine.CreateServer(
parsedAddress,
application));
}
}

if (!atLeastOneListener)
{
throw new InvalidOperationException("No recognized listening addresses were configured.");
}

return disposer;
}
catch
{
disposer.Dispose();
throw;
}
return new KestrelServer(serverFeatures, _appLifetime, _loggerFactory.CreateLogger("Microsoft.AspNet.Server.Kestrel"), _httpContextFactory);
}
}
}
4 changes: 4 additions & 0 deletions src/Microsoft.AspNet.Server.Kestrel/ServiceContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Server.Kestrel.Filter;
using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
Expand All @@ -20,6 +21,7 @@ public ServiceContext(ServiceContext context)
AppLifetime = context.AppLifetime;
Memory = context.Memory;
Log = context.Log;
HttpContextFactory = context.HttpContextFactory;
DateHeaderValueManager = context.DateHeaderValueManager;
ConnectionFilter = context.ConnectionFilter;
NoDelay = context.NoDelay;
Expand All @@ -31,6 +33,8 @@ public ServiceContext(ServiceContext context)

public IKestrelTrace Log { get; set; }

public IHttpContextFactory HttpContextFactory { get; set; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it need to be settable given that it is initialized in constructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


public DateHeaderValueManager DateHeaderValueManager { get; set; }

public IConnectionFilter ConnectionFilter { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public async Task RegisterAddresses_Success(string addressInput, string[] testUr
.Build();

var hostBuilder = new WebHostBuilder(config);
hostBuilder.UseServer("Microsoft.AspNet.Server.Kestrel");
hostBuilder.UseServerFactory("Microsoft.AspNet.Server.Kestrel");
hostBuilder.UseStartup(ConfigureEchoAddress);

using (var app = hostBuilder.Build().Start())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public async Task LargeUpload()
.Build();

var hostBuilder = new WebHostBuilder(config);
hostBuilder.UseServer("Microsoft.AspNet.Server.Kestrel");
hostBuilder.UseServerFactory("Microsoft.AspNet.Server.Kestrel");
hostBuilder.UseStartup(app =>
{
app.Run(async context =>
Expand Down
Loading