From 0814bc6b2dfccc14ce39e7c732ab4c6d7222c2e1 Mon Sep 17 00:00:00 2001 From: GHXX Date: Mon, 15 Jan 2024 19:56:14 +0100 Subject: [PATCH] Add static serving --- SimpleHttpServer/HttpServer.cs | 43 +++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/SimpleHttpServer/HttpServer.cs b/SimpleHttpServer/HttpServer.cs index a1b136d..1a78b66 100644 --- a/SimpleHttpServer/HttpServer.cs +++ b/SimpleHttpServer/HttpServer.cs @@ -187,13 +187,18 @@ public sealed class HttpServer { private async Task ProcessRequestAsync(HttpListenerContext ctx) { using RequestContext rc = new RequestContext(ctx); + var decUri = WebUtility.UrlDecode(ctx.Request.RawUrl)!; // TODO add path escape countermeasure-unittests + var splitted = decUri.Split('?', 2, StringSplitOptions.None); + var reqPath = NormalizeUrlPath(WebUtility.UrlDecode(splitted.First())); + string requestMethod = ctx.Request.HttpMethod.ToUpperInvariant(); + bool wasStaticlyServed = false; + + void LogRequest() { + requestLogger.Information($"{rc.ListenerContext.Response.StatusCode} {(wasStaticlyServed ? "static" : "endpnt")} {requestMethod} {decUri}"); + } try { - var decUri = WebUtility.UrlDecode(ctx.Request.RawUrl)!; // TODO add path escape countermeasures+unittests - var splitted = decUri.Split('?', 2, StringSplitOptions.None); - var reqPath = NormalizeUrlPath(WebUtility.UrlDecode(splitted.First())); - - if (simpleEndpointMethodInfos.TryGetValue((reqPath, ctx.Request.HttpMethod.ToUpperInvariant()), out var endpointInvocationInfo)) { + if (simpleEndpointMethodInfos.TryGetValue((reqPath, requestMethod), out var endpointInvocationInfo)) { var mi = endpointInvocationInfo.methodInfo; var qparams = endpointInvocationInfo.queryParameters; var args = splitted.Length == 2 ? splitted[1] : null; @@ -242,15 +247,29 @@ public sealed class HttpServer { await (Task) (mi.Invoke(null, convertedQParamValues) ?? throw new NullReferenceException("Website func returned null unexpectedly")); } else { + if (requestMethod == "GET") + foreach (var (k, v) in staticServePaths) { + if (reqPath.StartsWith(k)) { // do a static serve + wasStaticlyServed = true; + var relativeStaticReqPath = reqPath[k.Length..]; + var staticResponsePath = Path.Combine(v, relativeStaticReqPath); - foreach (var (k, v) in staticServePaths) { - if (k.StartsWith(reqPath)) { // do a static serve - // TODO finish and add path traversal checking + if (Path.GetRelativePath(v, staticResponsePath).Contains("..")) { + requestLogger.Warning($"Blocked GET request to {reqPath} as somehow the target file does not lie inside the static serve folder? Are you using symlinks?"); + await rc.SetStatusCodeAndDisposeAsync(HttpStatusCode.NotFound); + return; + } - - break; + if (File.Exists(staticResponsePath)) { + rc.SetStatusCode(HttpStatusCode.OK); + using var f = File.OpenRead(v); + await f.CopyToAsync(rc.ListenerContext.Response.OutputStream); + } else { + await rc.SetStatusCodeAndDisposeAsync(HttpStatusCode.NotFound); + } + return; + } } - } // invoke 404 await HandleDefaultErrorPageAsync(rc, 404); @@ -260,6 +279,8 @@ public sealed class HttpServer { await HandleDefaultErrorPageAsync(rc, 500); mainLogger.Fatal($"Caught otherwise uncaught exception while ProcessingRequest:\n{ex}"); } + + LogRequest(); }