High-performance HTTP request parser for .NET using zero-copy, span-based parsing.
Anvil.Http provides a small, fast HTTP request parser that operates on byte spans to avoid unnecessary allocations. It parses the request line, headers, and body with a focus on performance and minimal allocations.
- Zero-copy parsing using
ReadOnlySpan<byte>andref structtypes - Parses request line (method/path/version), headers, and body
- No dependencies; targets .NET 9.0
- This project was built for educational purposes and as a learning exercise. It is intended for use in personal projects, demos, and experimentation.
- It is not guaranteed to be production-ready; if you plan to use it in production systems, review it carefully and adapt it to your needs.
SpanBasedHttpParser and HttpRequestAccumulator work together as a system:
- HttpRequestAccumulator: Buffers incoming data chunks and tracks parsing state until a complete HTTP request is received
- SpanBasedHttpParser: Parses the accumulated complete request into structured components
// Server Loop - Accumulator buffers data, Parser processes complete requests
private async Task ProcessRequestAsync(NetworkStream stream)
{
using var accumulator = new HttpRequestAccumulator();
byte[] buffer = _pool.Rent(4096);
try
{
int read;
while ((read = await stream.ReadAsync(buffer)) != 0)
{
// Accumulator buffers incoming chunks and detects when complete
var result = accumulator.Accumulate(buffer.AsSpan(0, read));
if (result == AccumulatorResult.Complete)
{
// Get the complete accumulated request
var completeRequest = accumulator.GetAccumulatedData().ToArray();
Console.WriteLine($"Complete request: {completeRequest.Length} bytes");
// Parser processes the complete request
var parsedRequest = SpanBasedHttpParser.Parse(completeRequest);
// Map to Request object and handle
Request request = MapSpanToRequest(parsedRequest);
await HandleRouteAsync(request, stream);
// Reset accumulator for next request
accumulator.Reset();
}
}
}
finally
{
_pool.Return(buffer);
}
}From the src/Anvil.Http directory:
dotnet build -c ReleaseFor a detailed explanation of how the two-phase architecture works (buffering and parsing), see:
- FLOW.md — Comprehensive guide to the accumulator and parser flow, state machine transitions, and end-to-end examples with ASCII diagrams.
- CHANGELOG.md — Version history and feature tracking.
- The parser expects a full HTTP request with CRLF (
\r\n) line endings and a header terminator (\r\n\r\n). Content-Lengthis used to decide the body length when present.
MIT — see LICENSE file.
Contributions are welcome. Please open issues or pull requests on the repository:
