├── CONTRIBUTING.md ├── NuGet.config ├── dotnet-serve.sln.licenseheader ├── Directory.Build.targets ├── .vscode ├── tasks.json └── launch.json ├── .gitignore ├── src └── dotnet-serve │ ├── dotnet-serve.csproj │ ├── IPAddressAttribute.cs │ ├── Program.cs │ └── SimpleServer.cs ├── CHANGELOG.md ├── .appveyor.yml ├── version.props ├── .gitattributes ├── Directory.Build.props ├── README.md ├── dotnet-serve.sln ├── .editorconfig └── LICENSE.txt /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | A few simple rules for the road. 5 | 6 | 1. Before opening a PR with a significant change, open an issue so we can discuss design issues. 7 | 1. Play nice. 8 | -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /dotnet-serve.sln.licenseheader: -------------------------------------------------------------------------------- 1 | extensions: designer.cs generated.cs 2 | extensions: .cs 3 | // Copyright (c) Nate McMaster. 4 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 5 | -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "group": { 7 | "kind": "build", 8 | "isDefault": true 9 | }, 10 | "command": "dotnet", 11 | "type": "process", 12 | "args": [ 13 | "build", 14 | "--no-restore", 15 | "${workspaceFolder}/src/dotnet-serve/dotnet-serve.csproj" 16 | ], 17 | "problemMatcher": "$msCompile" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | [Oo]bj/ 2 | [Bb]in/ 3 | TestResults/ 4 | .nuget/ 5 | .build/ 6 | .testPublish/ 7 | *.sln.ide/ 8 | _ReSharper.*/ 9 | packages/ 10 | artifacts/ 11 | PublishProfiles/ 12 | .vs/ 13 | bower_components/ 14 | node_modules/ 15 | **/wwwroot/lib/ 16 | debugSettings.json 17 | project.lock.json 18 | *.user 19 | *.suo 20 | *.cache 21 | *.docstates 22 | _ReSharper.* 23 | *.exe 24 | *.psess 25 | *.vsp 26 | *.pidb 27 | *.userprefs 28 | *DS_Store 29 | *.ncrunchsolution 30 | *.*sdf 31 | *.ipch 32 | .settings 33 | *.sln.ide 34 | node_modules/ 35 | **/[Cc]ompiler/[Rr]esources/**/*.js 36 | .idea/ 37 | *.iml 38 | launchSettings.json 39 | 40 | -------------------------------------------------------------------------------- /src/dotnet-serve/dotnet-serve.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | true 7 | true 8 | dotnet-serve 9 | A simple command-line HTTP server. 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Launch (console)", 6 | "type": "coreclr", 7 | "request": "launch", 8 | "preLaunchTask": "build", 9 | "program": "${workspaceFolder}/.build/bin/dotnet-serve/Debug/netcoreapp2.1/dotnet-serve.dll", 10 | "args": [], 11 | "cwd": "${workspaceFolder}/src/dotnet-serve", 12 | "console": "internalConsole", 13 | "stopAtEntry": false, 14 | "internalConsoleOptions": "openOnSessionStart" 15 | }, 16 | { 17 | "name": ".NET Core Attach", 18 | "type": "coreclr", 19 | "request": "attach", 20 | "processId": "${command:pickProcess}" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /src/dotnet-serve/IPAddressAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Nate McMaster. 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 | 4 | using System.ComponentModel.DataAnnotations; 5 | using System.Net; 6 | 7 | namespace McMaster.DotNet.Server 8 | { 9 | sealed class IPAddressAttribute : ValidationAttribute 10 | { 11 | protected override ValidationResult IsValid(object value, ValidationContext context) 12 | { 13 | if (value is string str && !IPAddress.TryParse(str, out _)) 14 | { 15 | return new ValidationResult($"'{value}' is not a valid IP address"); 16 | } 17 | 18 | return ValidationResult.Success; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [Unreleased] 4 | 5 | Enhancements: 6 | - Add `--path-base` option to support setting a root URL to postpend to the site URL 7 | 8 | Fixes: 9 | - Launch the browser to localhost when 0.0.0.0 or [::] is used 10 | 11 | ## [v0.2.0] 12 | 13 | **March 13, 2018** 14 | 15 | Initial release of dotnet-serve as a global CLI tool. 16 | 17 | Changes: 18 | - Release the package as a DotnetTool package (global CLI tool) 19 | - Drop support for installing as a DotNetCliToolReference 20 | - Update to ASP.NET Core 2.1.0-preview1-final 21 | 22 | ## [v0.1.0] 23 | Initial release 24 | - Provides a simple command-line web server for dotnet 25 | 26 | [Unreleased]: https://github.com/natemcmaster/dotnet-serve/compare/v0.2.0...HEAD 27 | [v0.2.0]: https://github.com/natemcmaster/dotnet-serve/compare/v0.1.0...v0.2.0 28 | [v0.1.0]: https://github.com/natemcmaster/dotnet-serve/tree/v0.1.0 29 | 30 | -------------------------------------------------------------------------------- /src/dotnet-serve/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Nate McMaster. 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 | 4 | using System; 5 | using System.Threading.Tasks; 6 | using McMaster.Extensions.CommandLineUtils; 7 | 8 | namespace McMaster.DotNet.Server 9 | { 10 | class Program 11 | { 12 | // Return codes 13 | private const int ERROR = 2; 14 | private const int OK = 0; 15 | 16 | public static async Task Main(string[] args) 17 | { 18 | try 19 | { 20 | return await CommandLineApplication.ExecuteAsync(args); 21 | } 22 | catch (Exception ex) 23 | { 24 | Console.ForegroundColor = ConsoleColor.Red; 25 | Console.Error.WriteLine("Unexpected error: " + ex.ToString()); 26 | Console.ResetColor(); 27 | return ERROR; 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.2.1-alpha.{build} 2 | install: 3 | - ps: iwr https://raw.githubusercontent.com/dotnet/cli/release/2.1.3xx/scripts/obtain/dotnet-install.ps1 -outfile dotnet-install.ps1 4 | - ps: .\dotnet-install.ps1 -Version 2.1.300-preview1-008174 -InstallDir $env:ProgramFiles/dotnet 5 | branches: 6 | only: 7 | - master 8 | - appveyor 9 | - /^feature\/.*/ 10 | build_script: 11 | - ps: .\build.ps1 -IsOfficialBuild 12 | environment: 13 | global: 14 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true 15 | DOTNET_CLI_TELEMETRY_OPTOUT: 1 16 | test: off 17 | os: Visual Studio 2017 18 | artifacts: 19 | - path: 'artifacts\*.nupkg' 20 | name: Packages 21 | type: NuGetPackages 22 | deploy: 23 | - provider: NuGet 24 | name: myget 25 | artifact: Packages 26 | server: https://www.myget.org/F/natemcmaster/api/v2/package 27 | symbol_server: https://www.myget.org/F/natemcmaster/api/v2/package 28 | api_key: 29 | secure: KF1yGk4IHJyyfiHfFSCxJ+p5iZX+KPfCTnCihjD5iIZjasTS1lHeilpbaon4wvcM 30 | -------------------------------------------------------------------------------- /version.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0.2.1 4 | alpha 5 | $(VersionPrefix)-$(VersionSuffix) 6 | $(VersionPrefix) 7 | 8 | $(APPVEYOR_BUILD_NUMBER) 9 | 0 10 | $(VersionPrefix).$(BuildNumber) 11 | $(VersionSuffix).$(BuildNumber) 12 | 13 | 14 | 15 | 16 | <_Parameter1>BuildNumber 17 | <_Parameter2>$(BuildNumber) 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.doc diff=astextplain 2 | *.DOC diff=astextplain 3 | *.docx diff=astextplain 4 | *.DOCX diff=astextplain 5 | *.dot diff=astextplain 6 | *.DOT diff=astextplain 7 | *.pdf diff=astextplain 8 | *.PDF diff=astextplain 9 | *.rtf diff=astextplain 10 | *.RTF diff=astextplain 11 | 12 | *.jpg binary 13 | *.png binary 14 | *.gif binary 15 | 16 | *.cs text=auto diff=csharp 17 | *.vb text=auto 18 | *.resx text=auto 19 | *.c text=auto 20 | *.cpp text=auto 21 | *.cxx text=auto 22 | *.h text=auto 23 | *.hxx text=auto 24 | *.py text=auto 25 | *.rb text=auto 26 | *.java text=auto 27 | *.html text=auto 28 | *.htm text=auto 29 | *.css text=auto 30 | *.scss text=auto 31 | *.sass text=auto 32 | *.less text=auto 33 | *.js text=auto 34 | *.lisp text=auto 35 | *.clj text=auto 36 | *.sql text=auto 37 | *.php text=auto 38 | *.lua text=auto 39 | *.m text=auto 40 | *.asm text=auto 41 | *.erl text=auto 42 | *.fs text=auto 43 | *.fsx text=auto 44 | *.hs text=auto 45 | 46 | *.csproj text=auto 47 | *.vbproj text=auto 48 | *.fsproj text=auto 49 | *.dbproj text=auto 50 | *.sln text=auto eol=crlf 51 | 52 | *.sh eol=lf 53 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Nate McMaster 7 | dotnet-serve 8 | Copyright © Nate McMaster 9 | en-US 10 | false 11 | https://www.apache.org/licenses/LICENSE-2.0 12 | https://github.com/natemcmaster/dotnet-serve 13 | https://github.com/natemcmaster/dotnet-serve.git 14 | See $(PackageProjectUrl)/blob/master/CHANGELOG.md#v$(VersionPrefix.Replace('.','')) for release notes. 15 | git 16 | false 17 | true 18 | 7.1 19 | 20 | $(MSBuildThisFileDirectory)build\StrongName.snk 21 | true 22 | true 23 | 24 | true 25 | true 26 | 27 | $(MSBuildThisFileDirectory).build\obj\$(MSBuildProjectName) 28 | $(MSBuildThisFileDirectory).build\bin\$(MSBuildProjectName) 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dotnet-serve 2 | ============ 3 | 4 | [![AppVeyor build status][appveyor-badge]](https://ci.appveyor.com/project/natemcmaster/dotnet-serve/branch/master) 5 | 6 | [appveyor-badge]: https://img.shields.io/appveyor/ci/natemcmaster/dotnet-serve/master.svg?label=appveyor&style=flat-square 7 | 8 | [![NuGet][main-nuget-badge]][main-nuget] [![MyGet][main-myget-badge]][main-myget] 9 | 10 | [main-nuget]: https://www.nuget.org/packages/dotnet-serve/ 11 | [main-nuget-badge]: https://img.shields.io/nuget/v/dotnet-serve.svg?style=flat-square&label=nuget 12 | [main-myget]: https://www.myget.org/feed/natemcmaster/package/nuget/dotnet-serve 13 | [main-myget-badge]: https://img.shields.io/www.myget/natemcmaster/vpre/dotnet-serve.svg?style=flat-square&label=myget 14 | 15 | A simple command-line HTTP server. 16 | 17 | It launches a server in the current working directory and serves all files in it. 18 | 19 | ## Installation 20 | 21 | The latest release of dotnet-serve requires the [2.1.300-preview1](https://www.microsoft.com/net/download/dotnet-core/sdk-2.1.300-preview1) .NET Core SDK or newer. 22 | Once installed, run this command: 23 | 24 | ``` 25 | dotnet install tool --global dotnet-serve 26 | ``` 27 | 28 | ## Usage 29 | 30 | ``` 31 | dotnet serve [path] [options] 32 | 33 | Arguments: 34 | path Base path to the server root. Defaults to the current directory. 35 | 36 | Options: 37 | -p|--port Port to use [8080]. Use 0 for a dynamic port. 38 | -a|--address
Address to use [0.0.0.0] 39 | -o|--open-browser Open a web browser when the server starts [false] 40 | -?|-h|--help Show help information 41 | ``` 42 | -------------------------------------------------------------------------------- /dotnet-serve.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.26124.0 4 | MinimumVisualStudioVersion = 15.0.26124.0 5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C769ED8F-FD49-48BF-AE78-1F6ABCEAD42B}" 6 | EndProject 7 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-serve", "src\dotnet-serve\dotnet-serve.csproj", "{03156D3A-5F48-4F6B-8DAB-3ACED9241F1D}" 8 | EndProject 9 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1BABEE13-E148-472E-955A-1592CF8FC87E}" 10 | ProjectSection(SolutionItems) = preProject 11 | .appveyor.yml = .appveyor.yml 12 | .editorconfig = .editorconfig 13 | .gitattributes = .gitattributes 14 | .gitignore = .gitignore 15 | build.cmd = build.cmd 16 | build.ps1 = build.ps1 17 | CHANGELOG.md = CHANGELOG.md 18 | CONTRIBUTING.md = CONTRIBUTING.md 19 | Directory.Build.props = Directory.Build.props 20 | Directory.Build.targets = Directory.Build.targets 21 | dotnet-serve.sln.licenseheader = dotnet-serve.sln.licenseheader 22 | LICENSE.txt = LICENSE.txt 23 | NuGet.config = NuGet.config 24 | README.md = README.md 25 | version.props = version.props 26 | EndProjectSection 27 | EndProject 28 | Global 29 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 30 | Debug|Any CPU = Debug|Any CPU 31 | Release|Any CPU = Release|Any CPU 32 | EndGlobalSection 33 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 34 | {03156D3A-5F48-4F6B-8DAB-3ACED9241F1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {03156D3A-5F48-4F6B-8DAB-3ACED9241F1D}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {03156D3A-5F48-4F6B-8DAB-3ACED9241F1D}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {03156D3A-5F48-4F6B-8DAB-3ACED9241F1D}.Release|Any CPU.Build.0 = Release|Any CPU 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | GlobalSection(NestedProjects) = preSolution 43 | {03156D3A-5F48-4F6B-8DAB-3ACED9241F1D} = {C769ED8F-FD49-48BF-AE78-1F6ABCEAD42B} 44 | EndGlobalSection 45 | GlobalSection(ExtensibilityGlobals) = postSolution 46 | SolutionGuid = {9E6AF21B-9CC7-414F-8D8F-E12676569DB4} 47 | EndGlobalSection 48 | EndGlobal 49 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | trim_trailing_whitespace = true 6 | insert_final_newline = true 7 | 8 | [*.{xml,csproj,props,targets,config}] 9 | indent_size = 2 10 | 11 | [*.json] 12 | indent_size = 2 13 | 14 | [*.cs] 15 | indent_size = 4 16 | 17 | # Style I care about 18 | csharp_style_expression_bodied_constructors = false : error 19 | csharp_prefer_braces = true : error 20 | dotnet_sort_system_directives_first = true : error 21 | 22 | # Stuff that is usually best 23 | csharp_style_inlined_variable_declaration = true : warning 24 | csharp_style_var_elsewhere = true : warning 25 | csharp_space_after_cast = true : warning 26 | csharp_style_pattern_matching_over_as_with_null_check = true : warning 27 | csharp_style_pattern_matching_over_is_with_cast_check = true : warning 28 | csharp_style_var_for_built_in_types = true : warning 29 | csharp_style_var_when_type_is_apparent = true : warning 30 | csharp_new_line_before_catch = true : warning 31 | csharp_new_line_before_else = true : warning 32 | csharp_new_line_before_finally = true : warning 33 | csharp_indent_case_contents = true : warning 34 | csharp_new_line_before_open_brace = all 35 | csharp_indent_switch_labels = true : warning 36 | csharp_indent_labels = one_less_than_current 37 | csharp_prefer_simple_default_expression = true : warning 38 | 39 | # Good defaults, but not always 40 | dotnet_style_object_initializer = true : suggestion 41 | csharp_style_expression_bodied_indexers = true : suggestion 42 | csharp_style_expression_bodied_accessors = true : suggestion 43 | csharp_style_throw_expression = true : suggestion 44 | 45 | # Naming styles 46 | 47 | ## Constants are PascalCase 48 | dotnet_naming_style.pascal_case.capitalization = pascal_case 49 | 50 | dotnet_naming_symbols.constants.applicable_kinds = * 51 | dotnet_naming_symbols.constants.required_modifiers = const 52 | 53 | dotnet_naming_rule.constants_should_be_pascale_case.symbols = constants 54 | dotnet_naming_rule.constants_should_be_pascale_case.style = pascal_case 55 | dotnet_naming_rule.constants_should_be_pascale_case.severity = error 56 | 57 | ## Private static fields start with s_ 58 | dotnet_naming_style.s_underscore_camel_case.required_prefix = s_ 59 | dotnet_naming_style.s_underscore_camel_case.capitalization = camel_case 60 | 61 | dotnet_naming_symbols.private_static_fields.applicable_kinds = field 62 | dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private 63 | dotnet_naming_symbols.private_static_fields.required_modifiers = static 64 | 65 | dotnet_naming_rule.private_static_fields_should_be_underscore.symbols = private_static_fields 66 | dotnet_naming_rule.private_static_fields_should_be_underscore.style = s_underscore_camel_case 67 | dotnet_naming_rule.private_static_fields_should_be_underscore.severity = error 68 | 69 | ## Private fields are _camelCase 70 | dotnet_naming_style.underscore_camel_case.required_prefix = _ 71 | dotnet_naming_style.underscore_camel_case.capitalization = camel_case 72 | 73 | dotnet_naming_symbols.private_fields.applicable_kinds = field 74 | dotnet_naming_symbols.private_fields.applicable_accessibilities = private 75 | 76 | dotnet_naming_rule.private_fields_should_be_underscore.symbols = private_fields 77 | dotnet_naming_rule.private_fields_should_be_underscore.style = underscore_camel_case 78 | dotnet_naming_rule.private_fields_should_be_underscore.severity = error 79 | -------------------------------------------------------------------------------- /src/dotnet-serve/SimpleServer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Nate McMaster. 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 | 4 | using System; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Diagnostics; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Net; 10 | using System.Runtime.InteropServices; 11 | using System.Threading; 12 | using System.Threading.Tasks; 13 | using McMaster.Extensions.CommandLineUtils; 14 | using Microsoft.AspNetCore.Builder; 15 | using Microsoft.AspNetCore.Hosting; 16 | using Microsoft.AspNetCore.Hosting.Server.Features; 17 | using Microsoft.Extensions.Logging; 18 | using IOPath = System.IO.Path; 19 | 20 | namespace McMaster.DotNet.Server 21 | { 22 | [Command( 23 | Name = "dotnet serve", 24 | FullName = "dotnet-serve", 25 | Description = "Provides a simple HTTP server")] 26 | [HelpOption] 27 | class SimpleServer 28 | { 29 | [Argument(0, Name = "path", Description = "Base path to the server root")] 30 | [DirectoryExists] 31 | public string Path { get; } 32 | 33 | [Option(Description = "Port to use [8080]. Use 0 for a dynamic port.")] 34 | [Range(0, 65535, ErrorMessage = "Invalid port. Ports must be in the range of 0 to 65535.")] 35 | public int Port { get; } = 8080; 36 | 37 | [Option(Description = "Address to use [0.0.0.0]")] 38 | [IPAddress] 39 | public string Address { get; } = "0.0.0.0"; 40 | 41 | [Option(Description = "Open a web browser when the server starts. [false]")] 42 | public bool OpenBrowser { get; } 43 | 44 | [Option("--path-base ", Description = "The base URL path of postpended to the site url.")] 45 | public string PathBase { get; private set; } 46 | 47 | public async Task OnExecute(IConsole console) 48 | { 49 | var cts = new CancellationTokenSource(); 50 | console.CancelKeyPress += (o, e) => 51 | { 52 | console.WriteLine("Shutting down..."); 53 | cts.Cancel(); 54 | }; 55 | 56 | var address = IPAddress.Parse(Address); 57 | var path = Path != null 58 | ? IOPath.GetFullPath(Path) 59 | : Directory.GetCurrentDirectory(); 60 | 61 | if (!string.IsNullOrEmpty(PathBase) && PathBase[0] != '/') 62 | { 63 | PathBase = "/" + PathBase; 64 | } 65 | 66 | var host = new WebHostBuilder() 67 | .ConfigureLogging(l => 68 | { 69 | l.SetMinimumLevel(LogLevel.Information); 70 | l.AddConsole(); 71 | }) 72 | .PreferHostingUrls(false) 73 | .UseKestrel(o => 74 | { 75 | if (IPAddress.Any.Equals(address)) 76 | { 77 | o.ListenLocalhost(Port); 78 | o.ListenAnyIP(Port); 79 | } 80 | 81 | o.Listen(address, Port); 82 | }) 83 | .UseSockets() 84 | .UseWebRoot(path) 85 | .UseContentRoot(path) 86 | .UseEnvironment("Production") 87 | .Configure(app => 88 | { 89 | app.UseStatusCodePages("text/html", 90 | "Error {0}

HTTP {0}

"); 91 | 92 | if (!string.IsNullOrEmpty(PathBase)) 93 | { 94 | app.Map(PathBase, Configure); 95 | } 96 | else 97 | { 98 | Configure(app); 99 | } 100 | }) 101 | .Build(); 102 | 103 | console.ForegroundColor = ConsoleColor.DarkYellow; 104 | console.Write("Starting server, serving "); 105 | console.ResetColor(); 106 | console.WriteLine(IOPath.GetRelativePath(Directory.GetCurrentDirectory(), path)); 107 | 108 | await host.StartAsync(cts.Token); 109 | 110 | var addresses = host.ServerFeatures.Get(); 111 | 112 | console.WriteLine("Listening on:"); 113 | console.ForegroundColor = ConsoleColor.Green; 114 | foreach (var a in addresses.Addresses) 115 | { 116 | console.WriteLine(" " + a + PathBase); 117 | } 118 | 119 | console.ResetColor(); 120 | console.WriteLine(""); 121 | console.WriteLine("Press CTRL+C to exit"); 122 | 123 | if (OpenBrowser) 124 | { 125 | var url = addresses.Addresses.First(); 126 | // normalize to loopback if binding to IPAny 127 | url = url.Replace("0.0.0.0", "localhost"); 128 | url = url.Replace("[::]", "localhost"); 129 | 130 | if (!string.IsNullOrEmpty(PathBase)) 131 | { 132 | url += PathBase; 133 | } 134 | 135 | LaunchBrowser(url); 136 | } 137 | 138 | await host.WaitForShutdownAsync(cts.Token); 139 | return 0; 140 | } 141 | 142 | private static void Configure(IApplicationBuilder app) 143 | { 144 | app.UseFileServer(new FileServerOptions 145 | { 146 | EnableDefaultFiles = true, 147 | EnableDirectoryBrowsing = true, 148 | StaticFileOptions = 149 | { 150 | ServeUnknownFileTypes = true, 151 | }, 152 | }); 153 | } 154 | 155 | private static void LaunchBrowser(string url) 156 | { 157 | string processName; 158 | string[] args; 159 | if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 160 | { 161 | processName = "open"; 162 | args = new[] { url }; 163 | } 164 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 165 | { 166 | processName = "xdg-open"; 167 | args = new[] { url }; 168 | } 169 | else 170 | { 171 | processName = "cmd"; 172 | args = new[] { "/C", "start", url }; 173 | } 174 | 175 | Process.Start(processName, ArgumentEscaper.EscapeAndConcatenate(args)); 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | --------------------------------------------------------------------------------