diff --git a/Http11Probe.slnx b/Http11Probe.slnx index 21fa1cd..c088d0f 100644 --- a/Http11Probe.slnx +++ b/Http11Probe.slnx @@ -13,5 +13,6 @@ + diff --git a/docs/content/servers/effinitive.md b/docs/content/servers/effinitive.md new file mode 100644 index 0000000..1cf0e50 --- /dev/null +++ b/docs/content/servers/effinitive.md @@ -0,0 +1,178 @@ +--- +title: "Effinitive" +toc: false +breadcrumbs: false +--- + +**Language:** C# · [View source on GitHub](https://github.com/MDA2AV/Http11Probe/tree/main/src/Servers/EffinitiveServer) + +## Dockerfile + +```dockerfile +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +WORKDIR /src +COPY Directory.Build.props . +COPY src/Servers/EffinitiveServer/ src/Servers/EffinitiveServer/ +RUN dotnet restore src/Servers/EffinitiveServer/EffinitiveServer.csproj +RUN dotnet publish src/Servers/EffinitiveServer/EffinitiveServer.csproj -c Release -o /app --no-restore + +FROM mcr.microsoft.com/dotnet/runtime:10.0 +WORKDIR /app +COPY --from=build /app . +USER $APP_UID +ENTRYPOINT ["dotnet", "EffinitiveServer.dll", "8080"] +``` + +## Source — `Program.cs` + +```csharp +using System.Text; +using EffinitiveFramework.Core; +using EffinitiveFramework.Core.Http; + +var port = args.Length > 0 && int.TryParse(args[0], out var p) ? p : 8080; + +var app = EffinitiveApp + .Create() + .UsePort(port) + .MapEndpoints() + .Build(); + +Console.WriteLine($"Effinitive listening on http://localhost:{port}"); +await app.RunAsync(); + +namespace EffinitiveServer.Endpoints +{ + // ── GET / ────────────────────────────────────────────────────── + + sealed class GetRoot : NoRequestEndpointBase + { + protected override string Method => "GET"; + protected override string Route => "/"; + protected override string ContentType => Helpers.TextPlain; + + public override ValueTask HandleAsync(CancellationToken ct = default) + => ValueTask.FromResult("OK"); + } + + // ── POST / ───────────────────────────────────────────────────── + + sealed class PostRoot : NoRequestEndpointBase + { + protected override string Method => "POST"; + protected override string Route => "/"; + protected override string ContentType => Helpers.TextPlain; + + public override ValueTask HandleAsync(CancellationToken ct = default) + { + var body = HttpContext?.Body; + return ValueTask.FromResult(body is { Length: > 0 } ? Encoding.UTF8.GetString(body) : ""); + } + } + + // ── GET/POST /echo ──────────────────────────────────────────── + + sealed class EchoGet : NoRequestEndpointBase + { + protected override string Method => "GET"; + protected override string Route => "/echo"; + protected override string ContentType => Helpers.TextPlain; + + public override ValueTask HandleAsync(CancellationToken ct = default) + => ValueTask.FromResult(Helpers.EchoHeaders(HttpContext)); + } + + sealed class EchoPost : NoRequestEndpointBase + { + protected override string Method => "POST"; + protected override string Route => "/echo"; + protected override string ContentType => Helpers.TextPlain; + + public override ValueTask HandleAsync(CancellationToken ct = default) + => ValueTask.FromResult(Helpers.EchoHeaders(HttpContext)); + } + + // ── GET/POST /cookie ────────────────────────────────────────── + + sealed class CookieGet : NoRequestEndpointBase + { + protected override string Method => "GET"; + protected override string Route => "/cookie"; + protected override string ContentType => Helpers.TextPlain; + + public override ValueTask HandleAsync(CancellationToken ct = default) + => ValueTask.FromResult(Helpers.ParseCookies(HttpContext)); + } + + sealed class CookiePost : NoRequestEndpointBase + { + protected override string Method => "POST"; + protected override string Route => "/cookie"; + protected override string ContentType => Helpers.TextPlain; + + public override ValueTask HandleAsync(CancellationToken ct = default) + => ValueTask.FromResult(Helpers.ParseCookies(HttpContext)); + } + + // ── Shared helpers ──────────────────────────────────────────── + + static class Helpers + { + public const string TextPlain = "text/plain"; + + public static string EchoHeaders(HttpRequest? ctx) + { + if (ctx?.Headers is null) return ""; + var sb = new StringBuilder(); + foreach (var h in ctx.Headers) + sb.Append(h.Key).Append(": ").Append(h.Value).Append("\r\n"); + return sb.ToString(); + } + + public static string ParseCookies(HttpRequest? ctx) + { + if (ctx is null) return ""; + var sb = new StringBuilder(); + foreach (var c in ctx.Cookies) + sb.Append(c.Key).Append('=').Append(c.Value).Append("\r\n"); + return sb.ToString(); + } + } +} +``` + +## Test Results + +

Loading results...

+ +### Compliance + +
+ +### Smuggling + +
+ +### Malformed Input + +
+ +### Caching + +
+ +### Cookies + +
+ + + + diff --git a/src/Servers/EffinitiveServer/Dockerfile b/src/Servers/EffinitiveServer/Dockerfile new file mode 100644 index 0000000..ad3c2bc --- /dev/null +++ b/src/Servers/EffinitiveServer/Dockerfile @@ -0,0 +1,12 @@ +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +WORKDIR /src +COPY Directory.Build.props . +COPY src/Servers/EffinitiveServer/ src/Servers/EffinitiveServer/ +RUN dotnet restore src/Servers/EffinitiveServer/EffinitiveServer.csproj +RUN dotnet publish src/Servers/EffinitiveServer/EffinitiveServer.csproj -c Release -o /app --no-restore + +FROM mcr.microsoft.com/dotnet/runtime:10.0 +WORKDIR /app +COPY --from=build /app . +USER $APP_UID +ENTRYPOINT ["dotnet", "EffinitiveServer.dll", "8080"] diff --git a/src/Servers/EffinitiveServer/EffinitiveServer.csproj b/src/Servers/EffinitiveServer/EffinitiveServer.csproj new file mode 100644 index 0000000..dc4fd83 --- /dev/null +++ b/src/Servers/EffinitiveServer/EffinitiveServer.csproj @@ -0,0 +1,13 @@ + + + + Exe + net10.0 + false + + + + + + + diff --git a/src/Servers/EffinitiveServer/Program.cs b/src/Servers/EffinitiveServer/Program.cs new file mode 100644 index 0000000..d1eba00 --- /dev/null +++ b/src/Servers/EffinitiveServer/Program.cs @@ -0,0 +1,113 @@ +using System.Text; +using EffinitiveFramework.Core; +using EffinitiveFramework.Core.Http; + +var port = args.Length > 0 && int.TryParse(args[0], out var p) ? p : 8080; + +var app = EffinitiveApp + .Create() + .UsePort(port) + .MapEndpoints() + .Build(); + +Console.WriteLine($"Effinitive listening on http://localhost:{port}"); +await app.RunAsync(); + +namespace EffinitiveServer.Endpoints +{ + // ── GET / ────────────────────────────────────────────────────── + + sealed class GetRoot : NoRequestEndpointBase + { + protected override string Method => "GET"; + protected override string Route => "/"; + protected override string ContentType => Helpers.TextPlain; + + public override ValueTask HandleAsync(CancellationToken ct = default) + => ValueTask.FromResult("OK"); + } + + // ── POST / ───────────────────────────────────────────────────── + + sealed class PostRoot : NoRequestEndpointBase + { + protected override string Method => "POST"; + protected override string Route => "/"; + protected override string ContentType => Helpers.TextPlain; + + public override ValueTask HandleAsync(CancellationToken ct = default) + { + var body = HttpContext?.Body; + return ValueTask.FromResult(body is { Length: > 0 } ? Encoding.UTF8.GetString(body) : ""); + } + } + + // ── GET/POST /echo ──────────────────────────────────────────── + + sealed class EchoGet : NoRequestEndpointBase + { + protected override string Method => "GET"; + protected override string Route => "/echo"; + protected override string ContentType => Helpers.TextPlain; + + public override ValueTask HandleAsync(CancellationToken ct = default) + => ValueTask.FromResult(Helpers.EchoHeaders(HttpContext)); + } + + sealed class EchoPost : NoRequestEndpointBase + { + protected override string Method => "POST"; + protected override string Route => "/echo"; + protected override string ContentType => Helpers.TextPlain; + + public override ValueTask HandleAsync(CancellationToken ct = default) + => ValueTask.FromResult(Helpers.EchoHeaders(HttpContext)); + } + + // ── GET/POST /cookie ────────────────────────────────────────── + + sealed class CookieGet : NoRequestEndpointBase + { + protected override string Method => "GET"; + protected override string Route => "/cookie"; + protected override string ContentType => Helpers.TextPlain; + + public override ValueTask HandleAsync(CancellationToken ct = default) + => ValueTask.FromResult(Helpers.ParseCookies(HttpContext)); + } + + sealed class CookiePost : NoRequestEndpointBase + { + protected override string Method => "POST"; + protected override string Route => "/cookie"; + protected override string ContentType => Helpers.TextPlain; + + public override ValueTask HandleAsync(CancellationToken ct = default) + => ValueTask.FromResult(Helpers.ParseCookies(HttpContext)); + } + + // ── Shared helpers ──────────────────────────────────────────── + + static class Helpers + { + public const string TextPlain = "text/plain"; + + public static string EchoHeaders(HttpRequest? ctx) + { + if (ctx?.Headers is null) return ""; + var sb = new StringBuilder(); + foreach (var h in ctx.Headers) + sb.Append(h.Key).Append(": ").Append(h.Value).Append("\r\n"); + return sb.ToString(); + } + + public static string ParseCookies(HttpRequest? ctx) + { + if (ctx is null) return ""; + var sb = new StringBuilder(); + foreach (var c in ctx.Cookies) + sb.Append(c.Key).Append('=').Append(c.Value).Append("\r\n"); + return sb.ToString(); + } + } +} diff --git a/src/Servers/EffinitiveServer/probe.json b/src/Servers/EffinitiveServer/probe.json new file mode 100644 index 0000000..66a0a17 --- /dev/null +++ b/src/Servers/EffinitiveServer/probe.json @@ -0,0 +1 @@ +{"name": "Effinitive", "language": "C#"} \ No newline at end of file