An HTTP/1.1 server built from raw TCP sockets in C#, loosely following ThePrimeagen's boot.dev course for Go. Only I did it in C#.
(Why? Because I wanted to.)
dotnet build HttpFromTcp.slnxdotnet run --project HttpFromTcpThe server listens on 127.0.0.1:42069. Pass --debug (or -d) for verbose output:
dotnet run --project HttpFromTcp -- --debugSend a request with curl:
curl http://localhost:42069/# Run all tests
dotnet test HttpFromTcp.slnx
# Run a single test project
dotnet test HttpFromTcp.Tests/HttpFromTcp.Tests.csproj
dotnet test ErrorsTests/ErrorsTests.csproj
# Run a single test by name
dotnet test HttpFromTcp.Tests/HttpFromTcp.Tests.csproj --filter RequestReader_GoodLine_Succeeds| Project | Description |
|---|---|
HttpFromTcp |
The server. Accepts TCP connections and parses HTTP/1.1 requests using System.IO.Pipelines. |
Errors |
Standalone error library. Errors are tree-structured (Nil, Message, Tree) and composed with ErrorFuncs.Join(). |
HttpFromTcp.Tests |
xUnit v3 tests for the HTTP parser, including fragmented-stream tests that simulate slow network reads. |
ErrorsTests |
xUnit v2 tests for the Errors library. |
The server reads raw bytes from a TCP socket and incrementally parses HTTP/1.1 requests — no HttpListener, no ASP.NET, no Kestrel.
RequestReader uses a PipeReader and SequenceReader<byte> to parse request lines, headers, and bodies as data arrives. A state machine (Initialized → ReadingHeaders → ReadingBody → Done) drives the parsing so that incomplete reads simply wait for more data rather than failing.