Adding "server.urls" configuration support to kestrel
This commit is contained in:
parent
6ac6419f4f
commit
17e566c5d1
|
|
@ -25,6 +25,7 @@
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="ServerAddress.cs" />
|
||||||
<Compile Include="ServerFactory.cs" />
|
<Compile Include="ServerFactory.cs" />
|
||||||
<Compile Include="ServerInformation.cs" />
|
<Compile Include="ServerInformation.cs" />
|
||||||
<Compile Include="ServerRequest.cs" />
|
<Compile Include="ServerRequest.cs" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace Kestrel
|
||||||
|
{
|
||||||
|
public class ServerAddress
|
||||||
|
{
|
||||||
|
public string Host { get; internal set; }
|
||||||
|
public string Path { get; internal set; }
|
||||||
|
public int Port { get; internal set; }
|
||||||
|
public string Scheme { get; internal set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ using Microsoft.AspNet.Builder;
|
||||||
using Microsoft.Framework.ConfigurationModel;
|
using Microsoft.Framework.ConfigurationModel;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Server.Kestrel;
|
using Microsoft.AspNet.Server.Kestrel;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Kestrel
|
namespace Kestrel
|
||||||
{
|
{
|
||||||
|
|
@ -21,15 +22,30 @@ namespace Kestrel
|
||||||
|
|
||||||
public IDisposable Start(IServerInformation serverInformation, Func<object, Task> application)
|
public IDisposable Start(IServerInformation serverInformation, Func<object, Task> application)
|
||||||
{
|
{
|
||||||
|
var disposables = new List<IDisposable>();
|
||||||
var information = (ServerInformation)serverInformation;
|
var information = (ServerInformation)serverInformation;
|
||||||
var engine = new KestrelEngine();
|
var engine = new KestrelEngine();
|
||||||
engine.Start(1);
|
engine.Start(1);
|
||||||
engine.CreateServer(async frame =>
|
foreach (var address in information.Addresses)
|
||||||
{
|
{
|
||||||
var request = new ServerRequest(frame);
|
disposables.Add(engine.CreateServer(
|
||||||
await application.Invoke(request);
|
address.Scheme,
|
||||||
|
address.Host,
|
||||||
|
address.Port,
|
||||||
|
async frame =>
|
||||||
|
{
|
||||||
|
var request = new ServerRequest(frame);
|
||||||
|
await application.Invoke(request);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
disposables.Add(engine);
|
||||||
|
return new Disposable(() =>
|
||||||
|
{
|
||||||
|
foreach (var disposable in disposables)
|
||||||
|
{
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return engine;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,43 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNet.Builder;
|
using Microsoft.AspNet.Builder;
|
||||||
using Microsoft.Framework.ConfigurationModel;
|
using Microsoft.Framework.ConfigurationModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Kestrel
|
namespace Kestrel
|
||||||
{
|
{
|
||||||
public class ServerInformation : IServerInformation
|
public class ServerInformation : IServerInformation
|
||||||
{
|
{
|
||||||
|
public ServerInformation()
|
||||||
|
{
|
||||||
|
Addresses = new List<ServerAddress>();
|
||||||
|
}
|
||||||
|
|
||||||
public void Initialize(IConfiguration configuration)
|
public void Initialize(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
|
string urls;
|
||||||
|
if (!configuration.TryGet("server.urls", out urls))
|
||||||
|
{
|
||||||
|
urls = "http://+:5000/";
|
||||||
|
}
|
||||||
|
foreach (var url in urls.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
{
|
||||||
|
string scheme;
|
||||||
|
string host;
|
||||||
|
int port;
|
||||||
|
string path;
|
||||||
|
if (DeconstructUrl(url, out scheme, out host, out port, out path))
|
||||||
|
{
|
||||||
|
Addresses.Add(
|
||||||
|
new ServerAddress
|
||||||
|
{
|
||||||
|
Scheme = scheme,
|
||||||
|
Host = host,
|
||||||
|
Port = port,
|
||||||
|
Path = path
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
|
|
@ -17,5 +47,68 @@ namespace Kestrel
|
||||||
return "Kestrel";
|
return "Kestrel";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IList<ServerAddress> Addresses { get; private set; }
|
||||||
|
|
||||||
|
internal static bool DeconstructUrl(
|
||||||
|
string url,
|
||||||
|
out string scheme,
|
||||||
|
out string host,
|
||||||
|
out int port,
|
||||||
|
out string path)
|
||||||
|
{
|
||||||
|
url = url ?? string.Empty;
|
||||||
|
|
||||||
|
int delimiterStart1 = url.IndexOf("://", StringComparison.Ordinal);
|
||||||
|
if (delimiterStart1 < 0)
|
||||||
|
{
|
||||||
|
scheme = null;
|
||||||
|
host = null;
|
||||||
|
port = 0;
|
||||||
|
path = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int delimiterEnd1 = delimiterStart1 + "://".Length;
|
||||||
|
|
||||||
|
int delimiterStart3 = url.IndexOf("/", delimiterEnd1, StringComparison.Ordinal);
|
||||||
|
if (delimiterStart3 < 0)
|
||||||
|
{
|
||||||
|
delimiterStart3 = url.Length;
|
||||||
|
}
|
||||||
|
int delimiterStart2 = url.LastIndexOf(":", delimiterStart3 - 1, delimiterStart3 - delimiterEnd1, StringComparison.Ordinal);
|
||||||
|
int delimiterEnd2 = delimiterStart2 + ":".Length;
|
||||||
|
if (delimiterStart2 < 0)
|
||||||
|
{
|
||||||
|
delimiterStart2 = delimiterStart3;
|
||||||
|
delimiterEnd2 = delimiterStart3;
|
||||||
|
}
|
||||||
|
|
||||||
|
scheme = url.Substring(0, delimiterStart1);
|
||||||
|
string portString = url.Substring(delimiterEnd2, delimiterStart3 - delimiterEnd2);
|
||||||
|
int portNumber;
|
||||||
|
if (int.TryParse(portString, NumberStyles.Integer, CultureInfo.InvariantCulture, out portNumber))
|
||||||
|
{
|
||||||
|
host = url.Substring(delimiterEnd1, delimiterStart2 - delimiterEnd1);
|
||||||
|
port = portNumber;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (string.Equals(scheme, "http", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
port = 80;
|
||||||
|
}
|
||||||
|
else if (string.Equals(scheme, "https", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
port = 443;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
port = 0;
|
||||||
|
}
|
||||||
|
host = url.Substring(delimiterEnd1, delimiterStart3 - delimiterEnd1);
|
||||||
|
}
|
||||||
|
path = url.Substring(delimiterStart3);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
WriteAsync(buffer, offset, count).Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||||
|
|
|
||||||
|
|
@ -45,33 +45,35 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
Memory = memory;
|
Memory = memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync(KestrelThread thread, Func<Frame, Task> application)
|
public Task StartAsync(
|
||||||
|
string scheme,
|
||||||
|
string host,
|
||||||
|
int port,
|
||||||
|
KestrelThread thread,
|
||||||
|
Func<Frame, Task> application)
|
||||||
{
|
{
|
||||||
Thread = thread;
|
Thread = thread;
|
||||||
Application = application;
|
Application = application;
|
||||||
|
|
||||||
var tcs = new TaskCompletionSource<int>();
|
var tcs = new TaskCompletionSource<int>();
|
||||||
Thread.Post(OnStart, tcs);
|
Thread.Post(_ =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ListenSocket = new UvTcpHandle();
|
||||||
|
ListenSocket.Init(Thread.Loop);
|
||||||
|
ListenSocket.Bind(new IPEndPoint(IPAddress.Any, port));
|
||||||
|
ListenSocket.Listen(10, _connectionCallback, this);
|
||||||
|
tcs.SetResult(0);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
tcs.SetException(ex);
|
||||||
|
}
|
||||||
|
}, null);
|
||||||
return tcs.Task;
|
return tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnStart(object parameter)
|
|
||||||
{
|
|
||||||
var tcs = (TaskCompletionSource<int>)parameter;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ListenSocket = new UvTcpHandle();
|
|
||||||
ListenSocket.Init(Thread.Loop);
|
|
||||||
ListenSocket.Bind(new IPEndPoint(IPAddress.Any, 4001));
|
|
||||||
ListenSocket.Listen(10, _connectionCallback, this);
|
|
||||||
tcs.SetResult(0);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
tcs.SetException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnConnection(UvStreamHandle listenSocket, int status)
|
private void OnConnection(UvStreamHandle listenSocket, int status)
|
||||||
{
|
{
|
||||||
var acceptSocket = new UvTcpHandle();
|
var acceptSocket = new UvTcpHandle();
|
||||||
|
|
|
||||||
|
|
@ -48,13 +48,13 @@ namespace Microsoft.AspNet.Server.Kestrel
|
||||||
Threads.Clear();
|
Threads.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDisposable CreateServer(Func<Frame, Task> application)
|
public IDisposable CreateServer(string scheme, string host, int port, Func<Frame, Task> application)
|
||||||
{
|
{
|
||||||
var listeners = new List<Listener>();
|
var listeners = new List<Listener>();
|
||||||
foreach (var thread in Threads)
|
foreach (var thread in Threads)
|
||||||
{
|
{
|
||||||
var listener = new Listener(Memory);
|
var listener = new Listener(Memory);
|
||||||
listener.StartAsync(thread, application).Wait();
|
listener.StartAsync(scheme, host, port, thread, application).Wait();
|
||||||
listeners.Add(listener);
|
listeners.Add(listener);
|
||||||
}
|
}
|
||||||
return new Disposable(() =>
|
return new Disposable(() =>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
Server=Kestrel
|
||||||
|
; Server = Microsoft.AspNet.Server.WebListener
|
||||||
|
Server.Urls = http://localhost:5000/
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="libuv.dll" />
|
<Content Include="libuv.dll" />
|
||||||
|
<Content Include="Microsoft.AspNet.Hosting.ini" />
|
||||||
<Content Include="project.json" />
|
<Content Include="project.json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Kestrel": "0.1-alpha-*"
|
"Kestrel": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.Server.WebListener": "0.1-alpha-*"
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"net45": { },
|
"net45": { },
|
||||||
|
|
@ -11,6 +12,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
"web": "Microsoft.AspNet.Hosting --server kestrel"
|
"run": "Microsoft.AspNet.Hosting",
|
||||||
|
"web": "Microsoft.AspNet.Hosting"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Server.KestralTests
|
||||||
{
|
{
|
||||||
var engine = new KestrelEngine();
|
var engine = new KestrelEngine();
|
||||||
engine.Start(1);
|
engine.Start(1);
|
||||||
var started = engine.CreateServer(App);
|
var started = engine.CreateServer("http", "localhost", 54321, App);
|
||||||
started.Dispose();
|
started.Dispose();
|
||||||
engine.Dispose();
|
engine.Dispose();
|
||||||
}
|
}
|
||||||
|
|
@ -70,10 +70,10 @@ namespace Microsoft.AspNet.Server.KestralTests
|
||||||
{
|
{
|
||||||
var engine = new KestrelEngine();
|
var engine = new KestrelEngine();
|
||||||
engine.Start(1);
|
engine.Start(1);
|
||||||
var started = engine.CreateServer(App);
|
var started = engine.CreateServer("http", "localhost", 54321, App);
|
||||||
|
|
||||||
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||||
socket.Connect(new IPEndPoint(IPAddress.Loopback, 4001));
|
socket.Connect(new IPEndPoint(IPAddress.Loopback, 54321));
|
||||||
socket.Send(Encoding.ASCII.GetBytes("POST / HTTP/1.0\r\n\r\nHello World"));
|
socket.Send(Encoding.ASCII.GetBytes("POST / HTTP/1.0\r\n\r\nHello World"));
|
||||||
socket.Shutdown(SocketShutdown.Send);
|
socket.Shutdown(SocketShutdown.Send);
|
||||||
var buffer = new byte[8192];
|
var buffer = new byte[8192];
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Server.KestralTests
|
||||||
public void Create()
|
public void Create()
|
||||||
{
|
{
|
||||||
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||||
_socket.Connect(new IPEndPoint(IPAddress.Loopback, 4001));
|
_socket.Connect(new IPEndPoint(IPAddress.Loopback, 54321));
|
||||||
|
|
||||||
_stream = new NetworkStream(_socket, false);
|
_stream = new NetworkStream(_socket, false);
|
||||||
_reader = new StreamReader(_stream, Encoding.ASCII);
|
_reader = new StreamReader(_stream, Encoding.ASCII);
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,11 @@ namespace Microsoft.AspNet.Server.KestralTests
|
||||||
{
|
{
|
||||||
_engine = new KestrelEngine();
|
_engine = new KestrelEngine();
|
||||||
_engine.Start(1);
|
_engine.Start(1);
|
||||||
_server = _engine.CreateServer(app);
|
_server = _engine.CreateServer(
|
||||||
|
"http",
|
||||||
|
"localhost",
|
||||||
|
54321,
|
||||||
|
app);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue