HttpServerLite 2.1.5

dotnet add package HttpServerLite --version 2.1.5
NuGet\Install-Package HttpServerLite -Version 2.1.5
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="HttpServerLite" Version="2.1.5" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add HttpServerLite --version 2.1.5
#r "nuget: HttpServerLite, 2.1.5"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install HttpServerLite as a Cake Addin
#addin nuget:?package=HttpServerLite&version=2.1.5

// Install HttpServerLite as a Cake Tool
#tool nuget:?package=HttpServerLite&version=2.1.5

alt tag

HttpServerLite

NuGet Version NuGet

TCP-based user-space HTTP and HTTPS server, written in C#, with no dependency on http.sys.

New in v2.1.x

  • HostBuilder feature to quickly build servers, thank you @sapurtcomputer30!
  • Bugfix for HttpContext.HttpRequest.Data not ending, thank you @ChZhongPengCheng33

Special Thanks

I'd like to extend a special thanks to those that have provided motivation or otherwise directly helped make HttpServerLite better.

  • @winkmichael @Job79 @MartyIX @sqlnew @SaintedPsycho @Return25 @marcussacana @samisil
  • @Jump-Suit @sapurtcomputer30 @ChZhongPengCheng33

Performance

HttpServerLite is quite fast, however, it's in user-space and may be slower than other webservers that have the benefit of a kernel-mode driver (such as http.sys and IIS or Watson).

Getting Started

Refer to the Test project for a working example.

It is important to under that that HttpServerLite is minimalistic and leaves control to you on which headers are set. Thus it is important to understand the following:

  • server.Settings.Headers contains default values for a series of HTTP headers
    • These will be included in every response if they have a value assigned
    • The values in server.Settings.Headers can be written directly, or
      • You can modify per-response values by using ctx.Response.Headers.Add("[header]", "[value]")
      • Values set in ctx.Response.Headers will override any value in server.Settings.Headers for that response only
    • The headers automatically set if a value is supplied include
      • Access-Control-Allow-[Origin|Methods|Headers]
      • Access-Control-Expose-Headers
      • Accept
      • Accept-[Language|Charset]
      • Connection
      • Host
    • Connection is an example of one of these headers. By default it is set to close, therefore you should:
      • Leave it as is
      • Explicitly set it prior to sending a response using ctx.Response.Headers.Add("connection", "value"), or
      • Set the default value in server.Settings.Headers.Connection
  • ctx.Response.ContentLength should be set if you want the Content-Length header to be sent
  • server.Settings.Headers.Host should be set when instantiating the server though it is not required

Simple Server

using System;
using System.Threading.Tasks;
using HttpServerLite;

namespace Test
{
  class Program
  {
    static Webserver _Server;

    static void Main(string[] args)
    {
      Webserver server = new Webserver("localhost", 9000, false, null, null, DefaultRoute); 
      server.Settings.Headers.Host = "https://localhost:9000";
      server.Start();
      Console.WriteLine("HttpServerLite listening on http://localhost:9000");
      Console.WriteLine("ENTER to exit");
      Console.ReadLine();
    }
         
    static async Task DefaultRoute(HttpContext ctx)
    {
      string resp = "Hello from HttpServerLite!";
      ctx.Response.StatusCode = 200; 
      ctx.Response.ContentLength = resp.Length;
      ctx.Response.ContentType = "text/plain";
      await ctx.Response.SendAsync(resp);
    }
  }
} 

Routing

HttpServerLite includes the following routing capabilities. These are listed in the other in which they are processed within HttpServerLite:

  • server.Settings.AccessControl - access control based on IP address
    • You can specify the Mode to either be DefaultPermit or DefaultDeny
      • DefaultPermit will allow everything unless explicitly blocked through DenyList
      • DefaultDeny will deny everything unless explicitly permitted through PermitList
      • The default value is DefaultPermit
  • server.Routes.Preflight - a default route to use when the HTTP verb is OPTIONS
    • When set, the connection is terminated after being handled by server.OptionsRoute
  • server.Routes.PreRouting - a route through which all requests will pass, useful for authentication, logging, and other functions
    • If defined, return true from this task if you wish to terminate the connection
    • Otherwise return false to allow routing to continue
  • server.Routes.Content - serve GET and HEAD requests for static content based on URL path
    • Content will be read from the server.Routes.Content.BaseDirectory plus the URL path
    • An entire directory can be listed as a content route when adding the route
  • server.Routes.Static - invoke functions based on specific HTTP method and URL combinations
  • server.Routes.Parameter - invoke functions based on specific HTTP method and URLs with embedded parameters. These values are returned in HttpContext.HttpRequest.Url.Parameters
  • server.Routes.Dynamic - invoke functions based on specific HTTP method and a regular expression for the URL
  • server.Routes.Default - any request that did not match a content route, static route, or dynamic route, is routed here

Additionally, you can annotate your own methods using the StaticRoute, ParameterRoute, or DynamicRoute attributes. Methods decorated with these attributes must be marked as public.

Webserver server = new Webserver("localhost", 9000, false, null, null, DefaultRoute);
server.Start();

[StaticRoute(HttpMethod.GET, "/static")]
public static async Task MyStaticRoute(HttpContext ctx)
{
  string resp = "Hello from the static route";
  ctx.Response.StatusCode = 200;
  ctx.Response.ContentType = "text/plain";
  ctx.Response.ContentLength = resp.Length;
  await ctx.Response.SendAsync(resp);
  return;
}

[ParameterRoute(HttpMethod.GET, "/{version}/api/{id}")]
public static async Task MyParameterRoute(HttpContext ctx)
{
  string resp = "Hello from parameter route version " + ctx.Request.Url.Parameters["version"] + " for ID " + ctx.Request.Url.Parameters["id"];
  ctx.Response.StatusCode = 200;
  ctx.Response.ContentType = "text/plain";
  ctx.Response.ContentLength = resp.Length;
  await ctx.Response.SendAsync(resp);
  return;
}

[DynamicRoute(HttpMethod.GET, "^/dynamic/\\d+$")]
public static async Task MyDynamicRoute(HttpContext ctx)
{
  string resp = "Hello from the dynamic route";
  ctx.Response.StatusCode = 200;
  ctx.Response.ContentType = "text/plain";
  ctx.Response.ContentLength = resp.Length;
  await ctx.Response.SendAsync(resp);
  return;
}

Authorizing or Declining a Connection

server.Callbacks.AuthorizeConnection = AuthorizeConnection;

private static bool AuthorizeConnection(string ipAddress, int port)
{
  // evaluate the IP address and port
  return true;  // permit
  return false; // deny
}

HostBuilder

HostBuilder helps you set up your server much more easily by introducing a chain of settings and routes instead of using the server class directly.

using WatsonWebserver.Extensions.HostBuilderExtension;

Server server = new HostBuilder("127.0.0.1", 8000, false, DefaultRoute)
                .MapStaticRoute(WatsonWebserver.HttpMethod.GET, GetUrlsRoute, "/links")
                .MapStaticRoute(WatsonWebserver.HttpMethod.POST, CheckLoginRoute, "/login")
                .MapStaticRoute(WatsonWebserver.HttpMethod.POST, TestRoute, "/test")
                .Build();

server.Start();

Console.WriteLine("Server started");
Console.ReadKey();

static async Task DefaultRoute(HttpContext ctx) => 
    await ctx.Response.SendAsync("Hello from default route!"); 

static async Task GetUrlsRoute(HttpContext ctx) => 
    await ctx.Response.SendAsync("Here are your links!"); 

static async Task CheckLoginRoute(HttpContext ctx) => 
    await ctx.Response.SendAsync("Checking your login!"); 

static async Task TestRoute(HttpContext ctx) => 
    await ctx.Response.SendAsync("Hello from the test route!"); 

Accessing from Outside Localhost

When you configure HttpServerLite to listen on 127.0.0.1 or localhost, it will only respond to requests received from within the local machine.

To configure access from other nodes outside of localhost, use the following:

  • Specify the IP address on which HttpServerLite should listen in the Server constructor.
  • If you want to listen on more than one IP address, use * or +
  • If you listen on anything other than localhost or 127.0.0.1, you may have to run HttpServerLite as administrator (operating system dependent)
  • If you want to use a port number less than 1024, you MUST run HttpServerLite as administrator (this is an operating system limitation)
  • Open a port on your firewall to permit traffic on the TCP port upon which HttpServerLite is listening
  • If you're still having problems, please do not hesitate to file an issue here, and I will do my best to help and update the documentation

Version History

Refer to CHANGELOG.md for version history.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 is compatible. 
.NET Standard netstandard2.1 is compatible. 
.NET Framework net461 is compatible.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 is compatible.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.1.5 803 9/28/2023
2.1.4 1,766 8/3/2023
2.1.3 186 8/2/2023
2.1.2 1,880 7/5/2023
2.1.1 132 7/4/2023
2.1.0 146 7/4/2023
2.0.2 860 5/18/2023
2.0.1 118 5/18/2023
2.0.0 836 3/14/2023
1.2.12 1,136 1/27/2023
1.2.11 984 1/11/2023
1.2.10 1,652 11/26/2022
1.2.9 1,135 10/24/2022
1.2.8 520 10/12/2022
1.2.7 369 10/12/2022
1.2.6 2,222 8/8/2022
1.2.4 583 6/1/2022
1.2.3 610 5/19/2022
1.2.2 517 5/4/2022
1.2.1.11 546 4/1/2022
1.2.1.10 447 3/30/2022
1.2.1.8 472 2/18/2022
1.2.1.7 478 1/19/2022
1.2.1.6 523 1/13/2022
1.2.1.5 338 12/20/2021
1.2.1.4 268 12/20/2021
1.2.1.3 1,140 11/12/2021
1.2.1.2 2,153 10/6/2021
1.2.1.1 1,764 8/19/2021
1.2.1 4,088 2/22/2021
1.2.0 4,182 12/26/2020
1.1.0.2 520 12/26/2020
1.1.0.1 478 11/18/2020
1.0.6.1 410 11/11/2020
1.0.6 460 11/10/2020
1.0.5 501 11/9/2020
1.0.4 429 10/14/2020
1.0.3 438 10/14/2020
1.0.2 513 10/10/2020
1.0.1.1 1,906 8/30/2020
1.0.1 5,837 7/12/2020
1.0.0.16 979 6/30/2020

HostBuilder feature from @sapurtcomputer30