Skip to content

Commit baeef4f

Browse files
committed
Add Effinitive server implementation with Docker support
1 parent e8b0e78 commit baeef4f

6 files changed

Lines changed: 306 additions & 0 deletions

File tree

Http11Probe.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@
1313
<Project Path="src/Servers/SimpleWServer/SimpleWServer.csproj" />
1414
<Project Path="src/Servers/SiskServer/SiskServer.csproj" />
1515
<Project Path="src/Servers/ServiceStackServer/ServiceStackServer.csproj" />
16+
<Project Path="src/Servers/EffinitiveServer/EffinitiveServer.csproj" />
1617
</Folder>
1718
</Solution>

docs/content/servers/effinitive.md

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
---
2+
title: "Effinitive"
3+
toc: false
4+
breadcrumbs: false
5+
---
6+
7+
**Language:** C# · [View source on GitHub](https://github.com/MDA2AV/Http11Probe/tree/main/src/Servers/EffinitiveServer)
8+
9+
## Dockerfile
10+
11+
```dockerfile
12+
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
13+
WORKDIR /src
14+
COPY Directory.Build.props .
15+
COPY src/Servers/EffinitiveServer/ src/Servers/EffinitiveServer/
16+
RUN dotnet restore src/Servers/EffinitiveServer/EffinitiveServer.csproj
17+
RUN dotnet publish src/Servers/EffinitiveServer/EffinitiveServer.csproj -c Release -o /app --no-restore
18+
19+
FROM mcr.microsoft.com/dotnet/runtime:10.0
20+
WORKDIR /app
21+
COPY --from=build /app .
22+
ENTRYPOINT ["dotnet", "EffinitiveServer.dll", "8080"]
23+
```
24+
25+
## Source — `Program.cs`
26+
27+
```csharp
28+
using System.Text;
29+
using EffinitiveFramework.Core;
30+
using EffinitiveFramework.Core.Http;
31+
32+
var port = args.Length > 0 && int.TryParse(args[0], out var p) ? p : 8080;
33+
34+
var app = EffinitiveApp
35+
.Create()
36+
.UsePort(port)
37+
.MapEndpoints()
38+
.Build();
39+
40+
Console.WriteLine($"Effinitive listening on http://localhost:{port}");
41+
await app.RunAsync();
42+
43+
// ── GET / ──────────────────────────────────────────────────────
44+
45+
sealed class GetRoot : NoRequestEndpointBase<string>
46+
{
47+
protected override string Method => "GET";
48+
protected override string Route => "/";
49+
protected override string ContentType => "text/plain";
50+
51+
public override ValueTask<string> HandleAsync(CancellationToken ct = default)
52+
=> ValueTask.FromResult("OK");
53+
}
54+
55+
// ── POST / ─────────────────────────────────────────────────────
56+
57+
sealed class PostRoot : NoRequestEndpointBase<string>
58+
{
59+
protected override string Method => "POST";
60+
protected override string Route => "/";
61+
protected override string ContentType => "text/plain";
62+
63+
public override ValueTask<string> HandleAsync(CancellationToken ct = default)
64+
{
65+
var body = HttpContext?.Body;
66+
return ValueTask.FromResult(body is { Length: > 0 } ? Encoding.UTF8.GetString(body) : "");
67+
}
68+
}
69+
70+
// ── GET/POST /echo ────────────────────────────────────────────
71+
72+
sealed class EchoGet : NoRequestEndpointBase<string>
73+
{
74+
protected override string Method => "GET";
75+
protected override string Route => "/echo";
76+
protected override string ContentType => "text/plain";
77+
78+
public override ValueTask<string> HandleAsync(CancellationToken ct = default)
79+
=> ValueTask.FromResult(Helpers.EchoHeaders(HttpContext));
80+
}
81+
82+
sealed class EchoPost : NoRequestEndpointBase<string>
83+
{
84+
protected override string Method => "POST";
85+
protected override string Route => "/echo";
86+
protected override string ContentType => "text/plain";
87+
88+
public override ValueTask<string> HandleAsync(CancellationToken ct = default)
89+
=> ValueTask.FromResult(Helpers.EchoHeaders(HttpContext));
90+
}
91+
92+
// ── GET/POST /cookie ──────────────────────────────────────────
93+
94+
sealed class CookieGet : NoRequestEndpointBase<string>
95+
{
96+
protected override string Method => "GET";
97+
protected override string Route => "/cookie";
98+
protected override string ContentType => "text/plain";
99+
100+
public override ValueTask<string> HandleAsync(CancellationToken ct = default)
101+
=> ValueTask.FromResult(Helpers.ParseCookies(HttpContext));
102+
}
103+
104+
sealed class CookiePost : NoRequestEndpointBase<string>
105+
{
106+
protected override string Method => "POST";
107+
protected override string Route => "/cookie";
108+
protected override string ContentType => "text/plain";
109+
110+
public override ValueTask<string> HandleAsync(CancellationToken ct = default)
111+
=> ValueTask.FromResult(Helpers.ParseCookies(HttpContext));
112+
}
113+
114+
// ── Shared helpers ────────────────────────────────────────────
115+
116+
static class Helpers
117+
{
118+
public static string EchoHeaders(HttpRequest? ctx)
119+
{
120+
if (ctx?.Headers is null) return "";
121+
var sb = new StringBuilder();
122+
foreach (var h in ctx.Headers)
123+
sb.Append(h.Key).Append(": ").Append(h.Value).Append("\r\n");
124+
return sb.ToString();
125+
}
126+
127+
public static string ParseCookies(HttpRequest? ctx)
128+
{
129+
if (ctx is null) return "";
130+
var sb = new StringBuilder();
131+
foreach (var c in ctx.Cookies)
132+
sb.Append(c.Key).Append('=').Append(c.Value).Append("\r\n");
133+
return sb.ToString();
134+
}
135+
}
136+
```
137+
138+
## Test Results
139+
140+
<div id="server-summary"><p><em>Loading results...</em></p></div>
141+
142+
### Compliance
143+
144+
<div id="results-compliance"></div>
145+
146+
### Smuggling
147+
148+
<div id="results-smuggling"></div>
149+
150+
### Malformed Input
151+
152+
<div id="results-malformedinput"></div>
153+
154+
### Caching
155+
156+
<div id="results-capabilities"></div>
157+
158+
### Cookies
159+
160+
<div id="results-cookies"></div>
161+
162+
<script src="/probe/data.js"></script>
163+
<script src="/probe/render.js"></script>
164+
<script>
165+
(function() {
166+
if (!window.PROBE_DATA) {
167+
document.getElementById('server-summary').innerHTML = '<p><em>No probe data available yet. Run the Probe workflow on <code>main</code> to generate results.</em></p>';
168+
return;
169+
}
170+
ProbeRender.renderServerPage('Nginx');
171+
})();
172+
</script>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
2+
WORKDIR /src
3+
COPY Directory.Build.props .
4+
COPY src/Servers/EffinitiveServer/ src/Servers/EffinitiveServer/
5+
RUN dotnet restore src/Servers/EffinitiveServer/EffinitiveServer.csproj
6+
RUN dotnet publish src/Servers/EffinitiveServer/EffinitiveServer.csproj -c Release -o /app --no-restore
7+
8+
FROM mcr.microsoft.com/dotnet/runtime:10.0
9+
WORKDIR /app
10+
COPY --from=build /app .
11+
ENTRYPOINT ["dotnet", "EffinitiveServer.dll", "8080"]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<IsPackable>false</IsPackable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="EffinitiveFramework.Core" Version="1.3.*" />
11+
</ItemGroup>
12+
13+
</Project>
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
using System.Text;
2+
using EffinitiveFramework.Core;
3+
using EffinitiveFramework.Core.Http;
4+
5+
var port = args.Length > 0 && int.TryParse(args[0], out var p) ? p : 8080;
6+
7+
var app = EffinitiveApp
8+
.Create()
9+
.UsePort(port)
10+
.MapEndpoints()
11+
.Build();
12+
13+
Console.WriteLine($"Effinitive listening on http://localhost:{port}");
14+
await app.RunAsync();
15+
16+
// ── GET / ──────────────────────────────────────────────────────
17+
18+
sealed class GetRoot : NoRequestEndpointBase<string>
19+
{
20+
protected override string Method => "GET";
21+
protected override string Route => "/";
22+
protected override string ContentType => "text/plain";
23+
24+
public override ValueTask<string> HandleAsync(CancellationToken ct = default)
25+
=> ValueTask.FromResult("OK");
26+
}
27+
28+
// ── POST / ─────────────────────────────────────────────────────
29+
30+
sealed class PostRoot : NoRequestEndpointBase<string>
31+
{
32+
protected override string Method => "POST";
33+
protected override string Route => "/";
34+
protected override string ContentType => "text/plain";
35+
36+
public override ValueTask<string> HandleAsync(CancellationToken ct = default)
37+
{
38+
var body = HttpContext?.Body;
39+
return ValueTask.FromResult(body is { Length: > 0 } ? Encoding.UTF8.GetString(body) : "");
40+
}
41+
}
42+
43+
// ── GET/POST /echo ────────────────────────────────────────────
44+
45+
sealed class EchoGet : NoRequestEndpointBase<string>
46+
{
47+
protected override string Method => "GET";
48+
protected override string Route => "/echo";
49+
protected override string ContentType => "text/plain";
50+
51+
public override ValueTask<string> HandleAsync(CancellationToken ct = default)
52+
=> ValueTask.FromResult(Helpers.EchoHeaders(HttpContext));
53+
}
54+
55+
sealed class EchoPost : NoRequestEndpointBase<string>
56+
{
57+
protected override string Method => "POST";
58+
protected override string Route => "/echo";
59+
protected override string ContentType => "text/plain";
60+
61+
public override ValueTask<string> HandleAsync(CancellationToken ct = default)
62+
=> ValueTask.FromResult(Helpers.EchoHeaders(HttpContext));
63+
}
64+
65+
// ── GET/POST /cookie ──────────────────────────────────────────
66+
67+
sealed class CookieGet : NoRequestEndpointBase<string>
68+
{
69+
protected override string Method => "GET";
70+
protected override string Route => "/cookie";
71+
protected override string ContentType => "text/plain";
72+
73+
public override ValueTask<string> HandleAsync(CancellationToken ct = default)
74+
=> ValueTask.FromResult(Helpers.ParseCookies(HttpContext));
75+
}
76+
77+
sealed class CookiePost : NoRequestEndpointBase<string>
78+
{
79+
protected override string Method => "POST";
80+
protected override string Route => "/cookie";
81+
protected override string ContentType => "text/plain";
82+
83+
public override ValueTask<string> HandleAsync(CancellationToken ct = default)
84+
=> ValueTask.FromResult(Helpers.ParseCookies(HttpContext));
85+
}
86+
87+
// ── Shared helpers ────────────────────────────────────────────
88+
89+
static class Helpers
90+
{
91+
public static string EchoHeaders(HttpRequest? ctx)
92+
{
93+
if (ctx?.Headers is null) return "";
94+
var sb = new StringBuilder();
95+
foreach (var h in ctx.Headers)
96+
sb.Append(h.Key).Append(": ").Append(h.Value).Append("\r\n");
97+
return sb.ToString();
98+
}
99+
100+
public static string ParseCookies(HttpRequest? ctx)
101+
{
102+
if (ctx is null) return "";
103+
var sb = new StringBuilder();
104+
foreach (var c in ctx.Cookies)
105+
sb.Append(c.Key).Append('=').Append(c.Value).Append("\r\n");
106+
return sb.ToString();
107+
}
108+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"name": "Effinitive", "language": "C#"}

0 commit comments

Comments
 (0)