diff --git a/src/Kestrel/Kestrel.kproj b/src/Kestrel/Kestrel.kproj index 63934a9baa..0626b83124 100644 --- a/src/Kestrel/Kestrel.kproj +++ b/src/Kestrel/Kestrel.kproj @@ -25,6 +25,7 @@ 2.0 + diff --git a/src/Kestrel/ServerAddress.cs b/src/Kestrel/ServerAddress.cs new file mode 100644 index 0000000000..d5eac3be2b --- /dev/null +++ b/src/Kestrel/ServerAddress.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; } + } +} \ No newline at end of file diff --git a/src/Kestrel/ServerFactory.cs b/src/Kestrel/ServerFactory.cs index c4f3bf770e..a84ad1ae6e 100644 --- a/src/Kestrel/ServerFactory.cs +++ b/src/Kestrel/ServerFactory.cs @@ -4,6 +4,7 @@ using Microsoft.AspNet.Builder; using Microsoft.Framework.ConfigurationModel; using System.Threading.Tasks; using Microsoft.AspNet.Server.Kestrel; +using System.Collections.Generic; namespace Kestrel { @@ -21,15 +22,30 @@ namespace Kestrel public IDisposable Start(IServerInformation serverInformation, Func application) { + var disposables = new List(); var information = (ServerInformation)serverInformation; var engine = new KestrelEngine(); engine.Start(1); - engine.CreateServer(async frame => + foreach (var address in information.Addresses) { - var request = new ServerRequest(frame); - await application.Invoke(request); + disposables.Add(engine.CreateServer( + 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; } } } diff --git a/src/Kestrel/ServerInformation.cs b/src/Kestrel/ServerInformation.cs index ac8377a8f1..dc0dbc4399 100644 --- a/src/Kestrel/ServerInformation.cs +++ b/src/Kestrel/ServerInformation.cs @@ -1,13 +1,43 @@ using System; using Microsoft.AspNet.Builder; using Microsoft.Framework.ConfigurationModel; +using System.Globalization; +using System.Collections.Generic; namespace Kestrel { public class ServerInformation : IServerInformation { + public ServerInformation() + { + Addresses = new List(); + } + 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 @@ -17,5 +47,68 @@ namespace Kestrel return "Kestrel"; } } + + public IList 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; + } } -} \ No newline at end of file +} diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/FrameResponseStream.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/FrameResponseStream.cs index 756304ae0b..dc05b4dd7f 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/FrameResponseStream.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/FrameResponseStream.cs @@ -46,7 +46,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http 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) diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/Listener.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Listener.cs index 1b8a71b25e..123336ee6c 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/Listener.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Listener.cs @@ -45,33 +45,35 @@ namespace Microsoft.AspNet.Server.Kestrel.Http Memory = memory; } - public Task StartAsync(KestrelThread thread, Func application) + public Task StartAsync( + string scheme, + string host, + int port, + KestrelThread thread, + Func application) { Thread = thread; Application = application; var tcs = new TaskCompletionSource(); - 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; } - public void OnStart(object parameter) - { - var tcs = (TaskCompletionSource)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) { var acceptSocket = new UvTcpHandle(); diff --git a/src/Microsoft.AspNet.Server.Kestrel/KestrelEngine.cs b/src/Microsoft.AspNet.Server.Kestrel/KestrelEngine.cs index 6375b45fc6..78abaa224e 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/KestrelEngine.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/KestrelEngine.cs @@ -48,13 +48,13 @@ namespace Microsoft.AspNet.Server.Kestrel Threads.Clear(); } - public IDisposable CreateServer(Func application) + public IDisposable CreateServer(string scheme, string host, int port, Func application) { var listeners = new List(); foreach (var thread in Threads) { var listener = new Listener(Memory); - listener.StartAsync(thread, application).Wait(); + listener.StartAsync(scheme, host, port, thread, application).Wait(); listeners.Add(listener); } return new Disposable(() => diff --git a/src/SampleApp/Microsoft.AspNet.Hosting.ini b/src/SampleApp/Microsoft.AspNet.Hosting.ini new file mode 100644 index 0000000000..f0def9d26b --- /dev/null +++ b/src/SampleApp/Microsoft.AspNet.Hosting.ini @@ -0,0 +1,4 @@ + +Server=Kestrel +; Server = Microsoft.AspNet.Server.WebListener +Server.Urls = http://localhost:5000/ diff --git a/src/SampleApp/SampleApp.kproj b/src/SampleApp/SampleApp.kproj index c1ca9168bf..35a172e4e1 100644 --- a/src/SampleApp/SampleApp.kproj +++ b/src/SampleApp/SampleApp.kproj @@ -33,6 +33,7 @@ + diff --git a/src/SampleApp/project.json b/src/SampleApp/project.json index 1d23fd79d2..12bc80da47 100644 --- a/src/SampleApp/project.json +++ b/src/SampleApp/project.json @@ -1,6 +1,7 @@ { "dependencies": { - "Kestrel": "0.1-alpha-*" + "Kestrel": "0.1-alpha-*", + "Microsoft.AspNet.Server.WebListener": "0.1-alpha-*" }, "configurations": { "net45": { }, @@ -11,6 +12,7 @@ } }, "commands": { - "web": "Microsoft.AspNet.Hosting --server kestrel" + "run": "Microsoft.AspNet.Hosting", + "web": "Microsoft.AspNet.Hosting" } } diff --git a/test/Microsoft.AspNet.Server.KestralTests/EngineTests.cs b/test/Microsoft.AspNet.Server.KestralTests/EngineTests.cs index a40dcaaf70..e92e2a9b70 100644 --- a/test/Microsoft.AspNet.Server.KestralTests/EngineTests.cs +++ b/test/Microsoft.AspNet.Server.KestralTests/EngineTests.cs @@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Server.KestralTests { var engine = new KestrelEngine(); engine.Start(1); - var started = engine.CreateServer(App); + var started = engine.CreateServer("http", "localhost", 54321, App); started.Dispose(); engine.Dispose(); } @@ -70,10 +70,10 @@ namespace Microsoft.AspNet.Server.KestralTests { var engine = new KestrelEngine(); 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); - 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.Shutdown(SocketShutdown.Send); var buffer = new byte[8192]; diff --git a/test/Microsoft.AspNet.Server.KestralTests/TestConnection.cs b/test/Microsoft.AspNet.Server.KestralTests/TestConnection.cs index d07e0e4925..a1447fae25 100644 --- a/test/Microsoft.AspNet.Server.KestralTests/TestConnection.cs +++ b/test/Microsoft.AspNet.Server.KestralTests/TestConnection.cs @@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Server.KestralTests public void Create() { _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); _reader = new StreamReader(_stream, Encoding.ASCII); diff --git a/test/Microsoft.AspNet.Server.KestralTests/TestServer.cs b/test/Microsoft.AspNet.Server.KestralTests/TestServer.cs index 1efd5d95f5..4f8a2dd440 100644 --- a/test/Microsoft.AspNet.Server.KestralTests/TestServer.cs +++ b/test/Microsoft.AspNet.Server.KestralTests/TestServer.cs @@ -22,7 +22,11 @@ namespace Microsoft.AspNet.Server.KestralTests { _engine = new KestrelEngine(); _engine.Start(1); - _server = _engine.CreateServer(app); + _server = _engine.CreateServer( + "http", + "localhost", + 54321, + app); }