aboutsummaryrefslogtreecommitdiff
path: root/apps/VNLib.WebServer/src/Middlewares
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-08-04 17:14:10 -0400
committerLibravatar vnugent <public@vaughnnugent.com>2024-08-04 17:14:10 -0400
commit0419f315e5689e043f311203ab8e61f69f1ee1d6 (patch)
treef077b9d32d787bdef6e2cded203bc459a23dae7b /apps/VNLib.WebServer/src/Middlewares
parent7be5d6648e633ba46a270ca5784de6f4a5a4e0a9 (diff)
Squashed commit of the following:
commit bf6085a67a25c0242e3f170c3e617a08498d9ad0 Author: vnugent <public@vaughnnugent.com> Date: Sun Aug 4 16:58:09 2024 -0400 fix compression source tree and source package commit 4eb2cf913495e8a7c8c9ad3fceb3bff2a1b2a072 Author: vnugent <public@vaughnnugent.com> Date: Sun Aug 4 15:49:27 2024 -0400 push to codeberg commit 0b69bc760f87efab73ca6efb454b30a3393be269 Author: vnugent <public@vaughnnugent.com> Date: Sun Aug 4 15:36:26 2024 -0400 consolidate log config commit b8841c2218133bb8692e30cee0cfc719bfa5e9a0 Author: vnugent <public@vaughnnugent.com> Date: Thu Aug 1 21:30:59 2024 -0400 update compression copyright data and add package.json commit 08020ccace1474e27702ad6575259e799ca56b63 Merge: 904560a ff1765d Author: vnugent <public@vaughnnugent.com> Date: Thu Aug 1 21:26:47 2024 -0400 Merge branch 'develop' into slurp-webserver commit ff1765d3aa4d98fd223c47d16fca8e3e13a4d894 Author: vnugent <public@vaughnnugent.com> Date: Thu Aug 1 21:26:05 2024 -0400 set trasnport manager setters private for debug commit 904560a7b5eafd7580fb0a03e778d1751e72a503 Author: vnugent <public@vaughnnugent.com> Date: Thu Aug 1 21:13:04 2024 -0400 build(app): swallow vnlib.webserver into core & build updates commit 6af95e61212611908d39235222474d4038e10fcd Author: vnugent <public@vaughnnugent.com> Date: Wed Jul 31 15:14:07 2024 -0400 ci: clean up heapapi header & better formalize taskfiles commit 52965ce8bb0b06f59b07c7f6b5a9de6bfbc22b40 Author: vnugent <public@vaughnnugent.com> Date: Mon Jul 29 12:26:32 2024 -0400 move dev-init to module level for vnbuild module init commit e66b75642f654f623a3115bd3586d567d1554726 Merge: a4dacd2 7be5d66 Author: vnugent <public@vaughnnugent.com> Date: Sun Jul 28 19:16:13 2024 -0400 Merge branch 'master' into develop commit a4dacd2909426bf628c1eee1253cc5c8a01e2691 Author: vnugent <public@vaughnnugent.com> Date: Sat Jul 27 22:41:04 2024 -0400 package updates commit f836e09981866f5c9f2ae46990d11b186a7d12bb Author: vnugent <public@vaughnnugent.com> Date: Wed Jul 24 19:15:54 2024 -0400 chore: Remove argon2 docs & optional tcp resuse commit b9b892ab2143b0ab92e4dcf0a8b043c5c6c17271 Author: vnugent <public@vaughnnugent.com> Date: Sun Jul 21 20:57:01 2024 -0400 fix spelling Enqueue and deprecate mispelled version commit 21ffa816f18be4b765ad740ed5d93346ec3b1fda Author: vnugent <public@vaughnnugent.com> Date: Sat Jul 20 19:44:31 2024 -0400 static arugment list parsing functions commit 85cd6793818a3edd0a963bb4829a960ee6b0e022 Author: vnugent <public@vaughnnugent.com> Date: Mon Jul 15 18:58:06 2024 -0400 chore: Just some minor checks and adjustments commit abfb5761ee381b7e1e5342a5525ceca8c8fd81dd Author: vnugent <public@vaughnnugent.com> Date: Thu Jul 4 23:57:37 2024 -0400 analyzer pass commit 4a96dbb924f2b5bf80293e4054f221efe67151dd Author: vnugent <public@vaughnnugent.com> Date: Thu Jul 4 22:45:28 2024 -0400 package updates commit 38ad7d923fa8d9e463d4aaa8e35f021086a03f2d Author: vnugent <public@vaughnnugent.com> Date: Thu Jul 4 16:20:48 2024 -0400 mimalloc merge upstream upgrades commit 981ba286e4793de95bf65e6588313411344c4d53 Author: vnugent <public@vaughnnugent.com> Date: Thu Jul 4 16:04:03 2024 -0400 refactor: Refactor extensions with perf updates commit 6b8c67888731f7dd210acdb2b1160cdbdbe30d47 Author: vnugent <public@vaughnnugent.com> Date: Fri Jun 28 15:48:22 2024 -0400 refactor: Update service stack to reflect new loading patterns commit 12391e9a207b60b41a074600fc2373ad3eb1c3ab Author: vnugent <public@vaughnnugent.com> Date: Wed Jun 26 21:01:15 2024 -0400 feat(server): Server arch update, Memory struct access commit 92e182ceaf843f8d859d38faa8b2c0ff53207ff6 Author: vnugent <public@vaughnnugent.com> Date: Fri Jun 21 16:02:34 2024 -0400 feat: Multi transport listeners commit ee3620b8168a42c8e571e853c751ad5999a9b907 Author: vnugent <public@vaughnnugent.com> Date: Tue Jun 18 21:17:28 2024 -0400 feat: Add file path caching support commit ff0926be56fc6eafdce36411847d73bf4ce9f183 Author: vnugent <public@vaughnnugent.com> Date: Sun Jun 16 13:08:31 2024 -0400 feat: Allow multiple plugin loading directories commit 07ddf6738d32127926d07b1366e56d2a2308b53b Author: vnugent <public@vaughnnugent.com> Date: Sun Jun 16 01:12:07 2024 -0400 perf: Absolutely yuge perf boosts commit ff15c05a9c3e632c39f3889820fb7d889342b452 Author: vnugent <public@vaughnnugent.com> Date: Fri Jun 14 14:16:24 2024 -0400 fix: Improper request buffer property assignment commit 7d2987f1d4048c30808a85798e32c99747f6cfe3 Author: vnugent <public@vaughnnugent.com> Date: Thu Jun 13 21:57:34 2024 -0400 perf: Async pre-buffer to avoid sync buffer commit 75c1d0cbf9a5a7856c544671a45f1b4312ffe7ce Author: vnugent <public@vaughnnugent.com> Date: Tue Jun 11 22:11:45 2024 -0400 feat: Add a default site adapater and interceptors commit a7c739b7db9a17622cee751fe0e8a10e4b84b48b Author: vnugent <public@vaughnnugent.com> Date: Sun Jun 9 13:05:12 2024 -0400 chore: Package updated commit b4b506a4b6c7c1e90b5b0980e4cfe0460e7546a2 Author: vnugent <public@vaughnnugent.com> Date: Sat Jun 8 21:54:52 2024 -0400 some minor touchups commit 2160510fcc22a8574b0090fd91ca29072f45ab59 Author: vnugent <public@vaughnnugent.com> Date: Fri May 31 15:12:20 2024 -0400 refactor: Immutable tcp listeners commit 51cb4eb93e4f1b4c47d35b105e72af1fe771abcc Author: vnugent <public@vaughnnugent.com> Date: Thu May 30 17:31:16 2024 -0400 refactor: minor non-breaking changes to VNEncoding commit 768ddc1eb949266d693f96c67d734e881bd59374 Merge: 9a835fe 1b590c2 Author: vnugent <public@vaughnnugent.com> Date: Wed May 22 17:50:57 2024 -0400 Merge branch 'main' into develop commit 9a835fe12c9586ab8dd44d7c96fef4a2d6017e4b Author: vnugent <public@vaughnnugent.com> Date: Fri May 17 18:27:03 2024 -0400 chore: Update mimmaloc v2.1.6, update fPIC & cleanup commit 3b7004b88acfc7f7baa3a8857a5a2f7cf3dd560e Author: vnugent <public@vaughnnugent.com> Date: Fri May 17 16:03:28 2024 -0400 feat: Added ReadFileDataAsync function commit 9a964795757bf0da4dd7fcab15ad304f4ea3fdf1 Author: vnugent <public@vaughnnugent.com> Date: Wed May 15 21:57:39 2024 -0400 refactor: Harden some argon2 password hashing commit 4035c838c1508af0aa7e767a97431a692958ce1c Author: vnugent <public@vaughnnugent.com> Date: Sun May 12 16:55:32 2024 -0400 perf: Utils + http perf mods commit f4f0d4f74250257991c57bfae74c4852c7e1ae46 Author: vnugent <public@vaughnnugent.com> Date: Thu May 2 15:22:53 2024 -0400 feat: Buff middleware handlers | | Added implicit support for middleware post processing of files before the filehandler closes the connection. Also cleaned up some project file stuff commit f0b7dca107659df1d7d4631fdbd2aae9d716d053 Merge: 8c4a45e 107b058 Author: vnugent <public@vaughnnugent.com> Date: Sat Apr 20 12:24:05 2024 -0400 Merge branch 'main' into develop commit 8c4a45e384accf92b1b6d748530e8d46f7de40d6 Author: vnugent <public@vaughnnugent.com> Date: Sat Apr 20 11:10:30 2024 -0400 refactor: Overhaul C libraries and fix builds commit 42ff77080d10b0fc9fecbbc46141e8e23a1d066a Author: vnugent <public@vaughnnugent.com> Date: Sat Apr 20 00:45:57 2024 -0400 fix!: Middlware array, multiple cookie set, and cookie check commit 97e82b9d66f387f9e6d21d88ddc7a8ab8693149c Merge: 4ca5791 e07537a Author: vnugent <public@vaughnnugent.com> Date: Tue Apr 2 13:34:22 2024 -0400 Merge branch 'main' into develop commit 4ca5791ed67b9834bdbd010206b30373e4705e9b Author: vnugent <public@vaughnnugent.com> Date: Tue Apr 2 13:32:12 2024 -0400 fix: Missed ! on null pointer check commit 9b4036377c52200c6488c98180d69a0e63321f97 Author: vnugent <public@vaughnnugent.com> Date: Tue Apr 2 13:22:29 2024 -0400 fix: Fix _In_ macro for compression public api commit 53a7b4b5c5b67b4a4e06e1d9098cac4bcd6afd7c Merge: 448a93b 21130c8 Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 31 17:01:15 2024 -0400 Merge branch 'main' into develop commit 448a93bb1d18d032087afe2476ffccb98634a54c Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 31 16:56:51 2024 -0400 ci: fix third-party dir cleanup commit 9afed1427472da1ea13079f98dbe27339e55ee7d Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 31 16:43:15 2024 -0400 perf: Deprecate unsafememoryhandle span extensions commit 3ff90da4f02af47ea6d233fdd4445337ebe36452 Author: vnugent <public@vaughnnugent.com> Date: Sat Mar 30 21:36:18 2024 -0400 refactor: Updates, advanced tracing, http optimizations commit 8d6b79b5ae309b36f265ba81529bcef8bfcd7414 Merge: 6c1667b 5585915 Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 24 21:01:31 2024 -0400 Merge branch 'main' into develop commit 6c1667be23597513537f8190e2f55d65eb9b7c7a Author: vnugent <public@vaughnnugent.com> Date: Fri Mar 22 12:01:53 2024 -0400 refactor: Overhauled native library loading and lazy init commit ebf688f2f974295beabf7b5def7e6f6f150551d0 Author: vnugent <public@vaughnnugent.com> Date: Wed Mar 20 22:16:17 2024 -0400 refactor: Update compression header files and macros + Ci build commit 9c7b564911080ccd5cbbb9851a0757b05e1e9047 Author: vnugent <public@vaughnnugent.com> Date: Tue Mar 19 21:54:49 2024 -0400 refactor: JWK overhaul & add length getter to FileUpload commit 6d8c3444e09561e5957491b3cc1ae858e0abdd14 Author: vnugent <public@vaughnnugent.com> Date: Mon Mar 18 16:13:20 2024 -0400 feat: Add FNV1a software checksum and basic correction tests commit 00d182088cecefc08ca80b1faee9bed3f215f40b Author: vnugent <public@vaughnnugent.com> Date: Fri Mar 15 01:05:27 2024 -0400 chore: #6 Use utils filewatcher instead of built-in commit d513c10d9895c6693519ef1d459c6a5a76929436 Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 10 21:58:14 2024 -0400 source tree project location updated
Diffstat (limited to 'apps/VNLib.WebServer/src/Middlewares')
-rw-r--r--apps/VNLib.WebServer/src/Middlewares/BenchmarkMiddleware.cs102
-rw-r--r--apps/VNLib.WebServer/src/Middlewares/CORSMiddleware.cs182
-rw-r--r--apps/VNLib.WebServer/src/Middlewares/ConnectionLogMiddleware.cs108
-rw-r--r--apps/VNLib.WebServer/src/Middlewares/IpBlacklistMiddleware.cs49
-rw-r--r--apps/VNLib.WebServer/src/Middlewares/IpWhitelistMiddleware.cs53
-rw-r--r--apps/VNLib.WebServer/src/Middlewares/MainServerMiddlware.cs100
6 files changed, 594 insertions, 0 deletions
diff --git a/apps/VNLib.WebServer/src/Middlewares/BenchmarkMiddleware.cs b/apps/VNLib.WebServer/src/Middlewares/BenchmarkMiddleware.cs
new file mode 100644
index 0000000..2e2020c
--- /dev/null
+++ b/apps/VNLib.WebServer/src/Middlewares/BenchmarkMiddleware.cs
@@ -0,0 +1,102 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.WebServer
+* File: BenchmarkMiddleware.cs
+*
+* BenchmarkMiddleware.cs is part of VNLib.WebServer which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.WebServer is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.WebServer is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/.
+*/
+
+
+using System;
+using System.Net;
+using System.Buffers;
+using System.Diagnostics;
+using System.Threading.Tasks;
+using System.Security.Cryptography;
+
+using VNLib.Utils.Memory;
+using VNLib.Utils.Extensions;
+using VNLib.Net.Http;
+using VNLib.Plugins.Essentials;
+using VNLib.Plugins.Essentials.Middleware;
+
+using VNLib.WebServer.Config.Model;
+
+namespace VNLib.WebServer.Middlewares
+{
+ /*
+ * This is a cheatsy little syntethic benchmark middleware that will
+ * return a fixed size memory response for every request to simulate
+ * a file response for synthetic benchmarking.
+ *
+ * The buffer may optionally be filled with random data to put a
+ * load on the compressor instead of a zero filled buffer
+ */
+
+ internal sealed class BenchmarkMiddleware(BenchmarkConfig config) : IHttpMiddleware
+ {
+ private readonly MemoryManager<byte> data = AllocBuffer(config.Size, config.Random);
+
+ public ValueTask<FileProcessArgs> ProcessAsync(HttpEntity entity)
+ {
+ entity.CloseResponse(
+ HttpStatusCode.OK,
+ ContentType.Binary,
+ new BenchmarkResponseData(data.Memory)
+ );
+
+ return ValueTask.FromResult(FileProcessArgs.VirtualSkip);
+ }
+
+ private static MemoryManager<byte> AllocBuffer(int size, bool random)
+ {
+ /*
+ * Even though this is testing, the buffer is zeroed to avoid leaking
+ * any data that may be in heap memory after allocation.
+ */
+ MemoryManager<byte> man = MemoryUtil.Shared.DirectAlloc<byte>(size, true);
+
+ if (random)
+ {
+ RandomNumberGenerator.Fill(man.GetSpan());
+ }
+
+ return man;
+ }
+
+ private sealed class BenchmarkResponseData(ReadOnlyMemory<byte> data) : IMemoryResponseReader
+ {
+ int read;
+ readonly int len = data.Length;
+
+ public int Remaining => len - read;
+
+ public void Advance(int written)
+ {
+ read += written;
+ Debug.Assert(Remaining >= 0);
+ }
+
+ public void Close()
+ { }
+
+ public ReadOnlyMemory<byte> GetMemory() => data.Slice(read, Remaining);
+ }
+ }
+} \ No newline at end of file
diff --git a/apps/VNLib.WebServer/src/Middlewares/CORSMiddleware.cs b/apps/VNLib.WebServer/src/Middlewares/CORSMiddleware.cs
new file mode 100644
index 0000000..08b7cee
--- /dev/null
+++ b/apps/VNLib.WebServer/src/Middlewares/CORSMiddleware.cs
@@ -0,0 +1,182 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.WebServer
+* File: CORSMiddleware.cs
+*
+* CORSMiddleware.cs is part of VNLib.WebServer which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.WebServer is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.WebServer is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.Net;
+using System.Threading.Tasks;
+using System.Collections.Frozen;
+
+using VNLib.Net.Http;
+using VNLib.Utils.Logging;
+using VNLib.Plugins.Essentials;
+using VNLib.Plugins.Essentials.Sessions;
+using VNLib.Plugins.Essentials.Extensions;
+using VNLib.Plugins.Essentials.Middleware;
+
+using VNLib.WebServer.Config.Model;
+
+namespace VNLib.WebServer.Middlewares
+{
+
+ /// <summary>
+ /// Adds HTTP CORS protection to http servers
+ /// </summary>
+ /// <param name="Log"></param>
+ /// <param name="VirtualHostOptions"></param>
+ [MiddlewareImpl(MiddlewareImplOptions.SecurityCritical)]
+ internal sealed class CORSMiddleware(ILogProvider Log, CorsSecurityConfig secConfig) : IHttpMiddleware
+ {
+ private readonly FrozenSet<string> _corsAuthority = secConfig.AllowedCorsAuthority.ToFrozenSet(StringComparer.OrdinalIgnoreCase);
+
+ public ValueTask<FileProcessArgs> ProcessAsync(HttpEntity entity)
+ {
+ //Check coors enabled
+ bool isCors = entity.Server.IsCors();
+ bool isCrossSite = entity.Server.IsCrossSite();
+
+ /*
+ * Deny/allow cross site/cors requests at the site-level
+ */
+ if (!secConfig.DenyCorsCons)
+ {
+ //Confirm the origin is allowed during cors connections
+ if (entity.Server.CrossOrigin && _corsAuthority.Count > 0)
+ {
+ //If the authority is not allowed, deny the connection
+ if (!_corsAuthority.Contains(entity.Server.Origin!.Authority))
+ {
+ Log.Debug("Denied a connection from a cross-origin site {s}, the origin was not whitelisted", entity.Server.Origin);
+ return ValueTask.FromResult(FileProcessArgs.Deny);
+ }
+ }
+
+ if (isCors)
+ {
+ //set the allow credentials header
+ entity.Server.Headers["Access-Control-Allow-Credentials"] = "true";
+
+ //If cross site flag is set, or the connection has cross origin flag set, set explicit origin
+ if (entity.Server.CrossOrigin || isCrossSite && entity.Server.Origin != null)
+ {
+ entity.Server.Headers["Access-Control-Allow-Origin"] = $"{entity.Server.RequestUri.Scheme}://{entity.Server.Origin!.Authority}";
+ //Add origin to the response vary header when setting cors origin
+ entity.Server.Headers.Append(HttpResponseHeader.Vary, "Origin");
+ }
+ }
+
+ //Add sec vary headers for cors enabled sites
+ entity.Server.Headers.Append(HttpResponseHeader.Vary, "Sec-Fetch-Dest,Sec-Fetch-Mode,Sec-Fetch-Site");
+ }
+ else if (isCors | isCrossSite)
+ {
+ Log.Verbose("Denied a cross-site/cors request from {con} because this site does not allow cross-site/cors requests", entity.TrustedRemoteIp);
+ return ValueTask.FromResult(FileProcessArgs.Deny);
+ }
+
+ //If user-navigation is set and method is get, make sure it does not contain object/embed
+ if (entity.Server.IsNavigation() && entity.Server.Method == HttpMethod.GET)
+ {
+ string? dest = entity.Server.Headers["sec-fetch-dest"];
+ if (dest != null && (dest.Contains("object", StringComparison.OrdinalIgnoreCase) || dest.Contains("embed", StringComparison.OrdinalIgnoreCase)))
+ {
+ Log.Debug("Denied a browser navigation request from {con} because it contained an object/embed", entity.TrustedRemoteIp);
+ return ValueTask.FromResult(FileProcessArgs.Deny);
+ }
+ }
+
+ //If the connection is a cross-site, then an origin header must be supplied
+ if (isCrossSite && entity.Server.Origin is null)
+ {
+ Log.Debug("Denied cross-site request because origin header was not supplied");
+ return ValueTask.FromResult(FileProcessArgs.Deny);
+ }
+
+ //If same origin is supplied, enforce origin header on post/options/put/patch
+ if (string.Equals("same-origin", entity.Server.Headers["Sec-Fetch-Site"], StringComparison.OrdinalIgnoreCase))
+ {
+ //If method is not get/head, then origin is required
+ if ((entity.Server.Method & (HttpMethod.GET | HttpMethod.HEAD)) == 0 && entity.Server.Origin == null)
+ {
+ Log.Debug("Denied same-origin POST/PUT... request because origin header was not supplied");
+ return ValueTask.FromResult(FileProcessArgs.Deny);
+ }
+ }
+
+ if(!IsSessionSecured(entity))
+ {
+ return ValueTask.FromResult(FileProcessArgs.Deny);
+ }
+
+ return ValueTask.FromResult(FileProcessArgs.Continue);
+ }
+
+ private bool IsSessionSecured(HttpEntity entity)
+ {
+ ref readonly SessionInfo session = ref entity.Session;
+
+ /*
+ * When sessions are created for connections that come from a different
+ * origin, their origin is stored for later.
+ *
+ * If the session was created from a different origin or the current connection
+ * is cross origin, then the origin must be allowed by the configuration
+ */
+
+ //No session loaded, nothing to check
+ if (!session.IsSet)
+ {
+ return true;
+ }
+
+ if (entity.Server.Origin is null)
+ {
+ return true;
+ }
+
+ if (session.IsNew || session.SessionType != SessionType.Web)
+ {
+ return true;
+ }
+
+ bool sameOrigin = string.Equals(
+ entity.Server.Origin.Authority,
+ session.SpecifiedOrigin?.Authority,
+ StringComparison.OrdinalIgnoreCase
+ );
+
+ if (sameOrigin || _corsAuthority.Contains(entity.Server.Origin.Authority))
+ {
+ return true;
+ }
+
+ Log.Debug("Denied connection from {0} because the user's origin {org} changed to {other} and is not whitelisted.",
+ entity.TrustedRemoteIp,
+ session.SpecifiedOrigin?.Authority,
+ entity.Server.Origin.Authority
+ );
+
+ return false;
+ }
+ }
+} \ No newline at end of file
diff --git a/apps/VNLib.WebServer/src/Middlewares/ConnectionLogMiddleware.cs b/apps/VNLib.WebServer/src/Middlewares/ConnectionLogMiddleware.cs
new file mode 100644
index 0000000..939fd0d
--- /dev/null
+++ b/apps/VNLib.WebServer/src/Middlewares/ConnectionLogMiddleware.cs
@@ -0,0 +1,108 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.WebServer
+* File: ConnectionLogMiddleware.cs
+*
+* ConnectionLogMiddleware.cs is part of VNLib.WebServer which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.WebServer is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.WebServer is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/.
+*/
+
+/*
+ * Provides an Nginx-style log of incoming connections.
+ */
+
+using System.Threading.Tasks;
+using System.Security.Authentication;
+
+using VNLib.Net.Http;
+using VNLib.Utils.Logging;
+using VNLib.Plugins.Essentials;
+using VNLib.Plugins.Essentials.Middleware;
+
+namespace VNLib.WebServer.Middlewares
+{
+ internal sealed class ConnectionLogMiddleware(ILogProvider Log) : IHttpMiddleware
+ {
+ const string template = @"{ip} - {usr} [{local_time}] {tls} '{method} {url} {http_version}' {hostname} '{refer}' '{user_agent}' '{forwarded_for}'";
+
+ ///<inheritdoc/>
+ public ValueTask<FileProcessArgs> ProcessAsync(HttpEntity entity)
+ {
+ if (Log.IsEnabled(LogLevel.Information))
+ {
+ string userId = string.Empty;
+ if (entity.Session.IsSet)
+ {
+ userId = entity.Session.UserID;
+ }
+
+ Log.Information(template,
+ entity.TrustedRemoteIp,
+ userId,
+ entity.RequestedTimeUtc.ToLocalTime().ToString("dd/MMM/yyyy:HH:mm:ss zzz", null),
+ GetTlsInfo(entity),
+ entity.Server.Method,
+ entity.Server.RequestUri.PathAndQuery,
+ GetProtocolVersionString(entity),
+ entity.RequestedRoot.Hostname,
+ entity.Server.Referer,
+ entity.Server.UserAgent,
+ entity.Server.Headers["X-Forwarded-For"] ?? string.Empty
+ );
+ }
+
+ return ValueTask.FromResult(FileProcessArgs.Continue);
+ }
+
+ static string GetProtocolVersionString(HttpEntity entity)
+ {
+ return entity.Server.ProtocolVersion switch
+ {
+ HttpVersion.Http09 => "HTTP/0.9",
+ HttpVersion.Http1 => "HTTP/1.0",
+ HttpVersion.Http11 => "HTTP/1.1",
+ HttpVersion.Http2 => "HTTP/2.0",
+ HttpVersion.Http3 => "HTTP/3.0",
+ _ => "HTTP/1.1"
+ };
+ }
+
+ static string GetTlsInfo(HttpEntity entity)
+ {
+ ref readonly TransportSecurityInfo? secInfo = ref entity.Server.GetTransportSecurityInfo();
+
+ if(!secInfo.HasValue)
+ {
+ return string.Empty;
+ }
+
+#pragma warning disable CA5398, CA5397, SYSLIB0039 // Avoid hardcoded SslProtocols values
+
+ return secInfo.Value.SslProtocol switch
+ {
+ SslProtocols.Tls => "TLSv1.0",
+ SslProtocols.Tls11 => "TLSv1.1",
+ SslProtocols.Tls12 => "TLSv1.2",
+ SslProtocols.Tls13 => "TLSv1.3",
+ _ => "Unknown"
+ };
+
+#pragma warning restore CA5397, CA5398, SYSLIB0039 // Do not use deprecated SslProtocols values
+ }
+ }
+} \ No newline at end of file
diff --git a/apps/VNLib.WebServer/src/Middlewares/IpBlacklistMiddleware.cs b/apps/VNLib.WebServer/src/Middlewares/IpBlacklistMiddleware.cs
new file mode 100644
index 0000000..5959a95
--- /dev/null
+++ b/apps/VNLib.WebServer/src/Middlewares/IpBlacklistMiddleware.cs
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.WebServer
+* File: WhitelistMiddleware.cs
+*
+* WhitelistMiddleware.cs is part of VNLib.WebServer which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.WebServer is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.WebServer is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System.Net;
+using System.Threading.Tasks;
+using System.Collections.Frozen;
+
+using VNLib.Utils.Logging;
+using VNLib.Plugins.Essentials;
+using VNLib.Plugins.Essentials.Middleware;
+
+namespace VNLib.WebServer.Middlewares
+{
+ [MiddlewareImpl(MiddlewareImplOptions.SecurityCritical)]
+ internal sealed class IpBlacklistMiddleware(ILogProvider Log, FrozenSet<IPAddress> Blacklist) : IHttpMiddleware
+ {
+ public ValueTask<FileProcessArgs> ProcessAsync(HttpEntity entity)
+ {
+ if (Blacklist.Contains(entity.TrustedRemoteIp))
+ {
+ Log.Verbose("Client {ip} is blacklisted, blocked", entity.TrustedRemoteIp);
+ return ValueTask.FromResult(FileProcessArgs.Deny);
+ }
+
+ return ValueTask.FromResult(FileProcessArgs.Continue);
+ }
+ }
+} \ No newline at end of file
diff --git a/apps/VNLib.WebServer/src/Middlewares/IpWhitelistMiddleware.cs b/apps/VNLib.WebServer/src/Middlewares/IpWhitelistMiddleware.cs
new file mode 100644
index 0000000..bda754d
--- /dev/null
+++ b/apps/VNLib.WebServer/src/Middlewares/IpWhitelistMiddleware.cs
@@ -0,0 +1,53 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.WebServer
+* File: WhitelistMiddleware.cs
+*
+* WhitelistMiddleware.cs is part of VNLib.WebServer which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.WebServer is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.WebServer is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System.Net;
+using System.Threading.Tasks;
+using System.Collections.Frozen;
+
+using VNLib.Utils.Logging;
+using VNLib.Plugins.Essentials;
+using VNLib.Plugins.Essentials.Middleware;
+
+namespace VNLib.WebServer.Middlewares
+{
+ /*
+ * Middelware that matches clients real ip addresses against a whitelist
+ * and blocks them if they are not on the list
+ */
+ [MiddlewareImpl(MiddlewareImplOptions.SecurityCritical)]
+ internal sealed class IpWhitelistMiddleware(ILogProvider Log, FrozenSet<IPAddress> WhiteList) : IHttpMiddleware
+ {
+ public ValueTask<FileProcessArgs> ProcessAsync(HttpEntity entity)
+ {
+ if (!WhiteList.Contains(entity.TrustedRemoteIp))
+ {
+ Log.Verbose("Client {ip} is not whitelisted, blocked", entity.TrustedRemoteIp);
+ return ValueTask.FromResult(FileProcessArgs.Deny);
+ }
+
+ return ValueTask.FromResult(FileProcessArgs.Continue);
+ }
+ }
+} \ No newline at end of file
diff --git a/apps/VNLib.WebServer/src/Middlewares/MainServerMiddlware.cs b/apps/VNLib.WebServer/src/Middlewares/MainServerMiddlware.cs
new file mode 100644
index 0000000..da7eb3d
--- /dev/null
+++ b/apps/VNLib.WebServer/src/Middlewares/MainServerMiddlware.cs
@@ -0,0 +1,100 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.WebServer
+* File: MainServerMiddlware.cs
+*
+* MainServerMiddlware.cs is part of VNLib.WebServer which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.WebServer is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.WebServer is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System.Net;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+
+using VNLib.Net.Http;
+using VNLib.Utils.Logging;
+using VNLib.Plugins.Essentials;
+using VNLib.Plugins.Essentials.Extensions;
+using VNLib.Plugins.Essentials.Middleware;
+
+namespace VNLib.WebServer.Middlewares
+{
+
+ /// <summary>
+ /// Provides required/essential server functionality as a middelware processor
+ /// </summary>
+ /// <param name="Log"></param>
+ /// <param name="VirtualHostOptions"></param>
+ internal sealed class MainServerMiddlware(ILogProvider Log, VirtualHostConfig VirtualHostOptions, bool forcePorts) : IHttpMiddleware
+ {
+ public ValueTask<FileProcessArgs> ProcessAsync(HttpEntity entity)
+ {
+ //Set special server header
+ VirtualHostOptions.TrySetSpecialHeader(entity.Server, SpecialHeaders.Server);
+
+ //Block websocket requests
+ if (entity.Server.IsWebSocketRequest)
+ {
+ Log.Verbose("Client {ip} made a websocket request", entity.TrustedRemoteIp);
+ }
+
+ ref readonly TransportSecurityInfo? tlsSecInfo = ref entity.Server.GetTransportSecurityInfo();
+
+ //Check transport security if set
+ if (tlsSecInfo.HasValue)
+ {
+
+ }
+
+ //If not behind upstream server, uri ports and server ports must match
+ bool enforcePortCheck = !entity.IsBehindDownStreamServer && forcePorts;
+
+ if (enforcePortCheck && !entity.Server.EnpointPortsMatch())
+ {
+ Log.Debug("Connection {ip} received on port {p} but the client host port did not match at {pp}",
+ entity.TrustedRemoteIp,
+ entity.Server.LocalEndpoint.Port,
+ entity.Server.RequestUri.Port
+ );
+
+ return ValueTask.FromResult(FileProcessArgs.Deny);
+ }
+
+ /*
+ * downstream server will handle the transport security,
+ * if the connection is not from an downstream server
+ * and is using transport security then we can specify HSTS
+ */
+ if (entity.IsSecure)
+ {
+ VirtualHostOptions.TrySetSpecialHeader(entity.Server, SpecialHeaders.Hsts);
+ }
+
+ //Add response headers from vh config
+ for (int i = 0; i < VirtualHostOptions.AdditionalHeaders.Length; i++)
+ {
+ //Get and append the client header value
+ ref KeyValuePair<string, string> header = ref VirtualHostOptions.AdditionalHeaders[i];
+
+ entity.Server.Headers.Append(header.Key, header.Value);
+ }
+
+ return ValueTask.FromResult(FileProcessArgs.Continue);
+ }
+ }
+} \ No newline at end of file