diff --git a/README.md b/README.md index 8ea9f71..56a93fb 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,17 @@ dotnet serve -o dotnet serve -o -S ``` +... with a specific port (otherwise, it defaults to a random, unused port). +``` +dotnet serve --port 8080 +``` + +... with access allowed to remote machines (defaults to loopback only.) Use this if running inside Docker. + +``` +dotnet serve --address any +``` + ## Usage ``` @@ -45,7 +56,10 @@ Options: -d|--directory The root directory to serve. [Current directory] -o|--open-browser Open a web browser when the server starts. [false] -p|--port Port to use [8080]. Use 0 for a dynamic port. - -a|--address
Address to use [127.0.0.1] + -a|--address
Address to use. [Default = localhost]. + Accepts IP addresses, + 'localhost' for only accept requests from loopback connections, or + 'any' to accept requests from any IP address. --path-base The base URL path of postpended to the site url. --reverse-proxy Map a path pattern to another url. Expected format is =. diff --git a/src/dotnet-serve/CommandLineOptions.cs b/src/dotnet-serve/CommandLineOptions.cs index d705d7d..fa9836f 100644 --- a/src/dotnet-serve/CommandLineOptions.cs +++ b/src/dotnet-serve/CommandLineOptions.cs @@ -30,7 +30,7 @@ internal class CommandLineOptions [Range(0, 65535, ErrorMessage = "Invalid port. Ports must be in the range of 0 to 65535.")] public int? Port { get; internal set; } - [Option("-a|--address
", Description = "Address to use [127.0.0.1]")] + [Option("-a|--address
", Description = "Address to use. [Default = localhost].\nAccepts IP addresses,\n'localhost' for only accept requests from loopback connections, or\n'any' to accept requests from any IP address.")] public IPAddress[] Addresses { get; } [Option("--path-base ", Description = "The base URL path of postpended to the site url.")] diff --git a/src/dotnet-serve/IPAddressParser.cs b/src/dotnet-serve/IPAddressParser.cs index 59fb976..377095e 100644 --- a/src/dotnet-serve/IPAddressParser.cs +++ b/src/dotnet-serve/IPAddressParser.cs @@ -18,6 +18,11 @@ public IPAddress Parse(string argName, string value, CultureInfo culture) return IPAddress.Loopback; } + if (string.Equals("any", value, StringComparison.OrdinalIgnoreCase)) + { + return IPAddress.IPv6Any; + } + if (!IPAddress.TryParse(value, out var address)) { throw new FormatException($"'{value}' is not a valid IP address"); diff --git a/src/dotnet-serve/SimpleServer.cs b/src/dotnet-serve/SimpleServer.cs index db1ebd2..22f3080 100644 --- a/src/dotnet-serve/SimpleServer.cs +++ b/src/dotnet-serve/SimpleServer.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Diagnostics; +using System.Net; using System.Runtime.InteropServices; using McMaster.Extensions.CommandLineUtils; using Microsoft.AspNetCore.Hosting; @@ -80,7 +81,14 @@ void ConfigureHttps(ListenOptions options) { foreach (var a in _options.Addresses) { - o.Listen(a, port.GetValueOrDefault(), ConfigureHttps); + if (a == IPAddress.IPv6Any) + { + o.ListenAnyIP(port.GetValueOrDefault(), ConfigureHttps); + } + else + { + o.Listen(a, port.GetValueOrDefault(), ConfigureHttps); + } } } }) @@ -103,12 +111,13 @@ void ConfigureHttps(ListenOptions options) } await host.StartAsync(cancellationToken); - AfterServerStart(host); + var logger = host.Services.GetRequiredService>(); + AfterServerStart(host, logger); await host.WaitForShutdownAsync(cancellationToken); return 0; } - private void AfterServerStart(IWebHost host) + private void AfterServerStart(IWebHost host, ILogger logger) { var addresses = host.ServerFeatures.Get(); var pathBase = _options.GetPathBase(); @@ -116,6 +125,7 @@ private void AfterServerStart(IWebHost host) _console.WriteLine(GetListeningAddressText(addresses)); foreach (var a in addresses.Addresses) { + logger.LogDebug("Listening on {address}", a); _console.WriteLine(ConsoleColor.Green, " " + NormalizeToLoopbackAddress(a) + pathBase); } @@ -158,7 +168,7 @@ static string NormalizeToLoopbackAddress(string url) } } - private static void LaunchBrowser(string url) + private void LaunchBrowser(string url) { var psi = new ProcessStartInfo(); if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) @@ -171,13 +181,18 @@ private static void LaunchBrowser(string url) psi.FileName = "xdg-open"; psi.ArgumentList.Add(url); } - else + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { psi.FileName = "cmd"; psi.ArgumentList.Add("/C"); psi.ArgumentList.Add("start"); psi.ArgumentList.Add(url); } + else + { + _console.Write(ConsoleColor.Red, "Could not determine how to launch the browser for this OS platform."); + return; + } Process.Start(psi); }