|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +TurboHttp is a high-performance HTTP protocol implementation library for .NET using Akka.NET streaming. It implements HTTP/1.0, HTTP/1.1, and HTTP/2 protocols with full RFC compliance. |
| 8 | + |
| 9 | +## Build Commands |
| 10 | + |
| 11 | +```bash |
| 12 | +# Restore and build |
| 13 | +dotnet restore ./src/TurboHttp.sln |
| 14 | +dotnet build --configuration Release ./src/TurboHttp.sln |
| 15 | + |
| 16 | +# Run all tests |
| 17 | +dotnet test ./src/TurboHttp.sln |
| 18 | + |
| 19 | +# Run specific test class |
| 20 | +dotnet test ./src/TurboHttp.Tests/TurboHttp.Tests.csproj --filter "ClassName=TurboHttp.Tests.HpackTests" |
| 21 | + |
| 22 | +# Run specific test method |
| 23 | +dotnet test ./src/TurboHttp.Tests/TurboHttp.Tests.csproj --filter "FullyQualifiedName~HpackTests.Encode_Decode_RoundTrip" |
| 24 | + |
| 25 | +# Run benchmarks |
| 26 | +dotnet run --configuration Release ./src/TurboHttp.Benchmarks/TurboHttp.Benchmarks.csproj" |
| 27 | +``` |
| 28 | +
|
| 29 | +## Architecture |
| 30 | +
|
| 31 | +### Layered Design |
| 32 | +
|
| 33 | +``` |
| 34 | +Protocol Layer (TurboHttp/Protocol/) |
| 35 | + HTTP 1.0/1.1/2 Encoders/Decoders, HPACK compression |
| 36 | + ↓ |
| 37 | +I/O Layer (TurboHttp/IO/) |
| 38 | + Akka Actors + TcpClient + System.Threading.Channels |
| 39 | + ↓ |
| 40 | +Network (TcpStream) |
| 41 | +``` |
| 42 | +
|
| 43 | +### Protocol Layer (`TurboHttp/Protocol/`) |
| 44 | +
|
| 45 | +**Encoders** - Stateless, static methods that serialize `HttpRequestMessage` to bytes: |
| 46 | +- `Http10Encoder.Encode()`, `Http11Encoder.Encode()`, `Http2Encoder.Encode()` |
| 47 | +- Use `ref Span<byte>` or `ref Memory<byte>` for zero-allocation patterns |
| 48 | +
|
| 49 | +**Decoders** - Stateful classes that handle partial frame buffering across TCP boundaries: |
| 50 | +- Maintain `_remainder` field for incomplete messages |
| 51 | +- Methods: `TryDecode()` for normal parsing, `TryDecodeEof()` for connection close scenarios |
| 52 | +- `Reset()` to clear state between connections |
| 53 | +
|
| 54 | +**HPACK (RFC 7541)** - Stateful header compression for HTTP/2: |
| 55 | +- `HpackEncoder`/`HpackDecoder` maintain synchronized dynamic tables |
| 56 | +- `HpackDynamicTable` - FIFO queue with 32-byte per-entry overhead |
| 57 | +- `HuffmanCodec` - Static Huffman encoding/decoding |
| 58 | +- Sensitive headers (Authorization, Cookie) automatically use NeverIndex |
| 59 | +
|
| 60 | +### I/O Layer (`TurboHttp/IO/`) |
| 61 | +
|
| 62 | +Actor-based connection management using Akka.NET: |
| 63 | +- `TcpConnectionManagerActor` - Supervises TCP connections |
| 64 | +- `TcpClientRunner` - Per-connection lifecycle actor |
| 65 | +- `TcpClientState` - Shared state wrapper (channels + buffers) |
| 66 | +- `TcpClientByteMover` - Async byte transfer between TCP and channels |
| 67 | +
|
| 68 | +### HTTP/2 Frame Types (`Http2Frame.cs`) |
| 69 | +
|
| 70 | +All frame types inherit from `Http2Frame` base class with: |
| 71 | +- `SerializedSize` property for buffer pre-allocation |
| 72 | +- `WriteTo(ref Span<byte>)` for serialization |
| 73 | +- Frame header: 9 bytes (length:24, type:8, flags:8, stream:31) |
| 74 | +
|
| 75 | +## Key Patterns |
| 76 | +
|
| 77 | +### Memory Management |
| 78 | +- Use `ReadOnlyMemory<byte>` and `Span<T>` for buffer efficiency |
| 79 | +- `IMemoryOwner<byte>` requires proper disposal |
| 80 | +- `IBufferWriter<byte>` for zero-copy encoding output |
| 81 | +
|
| 82 | +### Error Handling |
| 83 | +- `HpackException` - RFC 7541 violations |
| 84 | +- `Http2Exception` - HTTP/2 protocol errors |
| 85 | +- `HttpDecoderException` - General decode failures |
| 86 | +- `HttpDecodeError` enum for error classification |
| 87 | +
|
| 88 | +## Code Style and Conventions |
| 89 | +
|
| 90 | +### C# Style |
| 91 | +- Allman style braces (opening brace on new line) |
| 92 | +- 4 spaces indentation, no tabs |
| 93 | +- Private fields prefixed with underscore `_fieldName` |
| 94 | +- Use `var` when type is apparent |
| 95 | +- Default to `sealed` classes and records |
| 96 | +- Enable `#nullable enable` in new/modified files |
| 97 | +- Never use `async void`, `.Result`, or `.Wait()` |
| 98 | +- Always pass `CancellationToken` through async call chains |
| 99 | +- Always use braces for control structures (even single-line statements) |
| 100 | +
|
| 101 | +### API Design |
| 102 | +- Use `Task<T>` instead of Future, `TimeSpan` instead of Duration |
| 103 | +- Extend-only design - don't modify existing public APIs |
| 104 | +- Preserve wire format compatibility for serialization |
| 105 | +- Include unit tests with all changes |
| 106 | +
|
| 107 | +### Test Naming |
| 108 | +- Use `DisplayName` attribute for descriptive test names |
| 109 | +- Follow pattern: `Should_ExpectedBehavior_When_Condition` |
| 110 | +
|
| 111 | +# Agent Guidance: dotnet-skills |
| 112 | +
|
| 113 | +IMPORTANT: Prefer retrieval-led reasoning over pretraining for any .NET work. |
| 114 | +Workflow: skim repo patterns -> consult dotnet-skills by name -> implement smallest-change -> note conflicts. |
| 115 | +
|
| 116 | +Routing (invoke by name) |
| 117 | +- C# / code quality: modern-csharp-coding-standards, csharp-concurrency-patterns, api-design, type-design-performance |
| 118 | +- ASP.NET Core / Web (incl. Aspire): aspire-service-defaults, aspire-integration-testing, transactional-emails |
| 119 | +- Data: efcore-patterns, database-performance |
| 120 | +- DI / config: dependency-injection-patterns, microsoft-extensions-configuration |
| 121 | +- Testing: testcontainers-integration-tests, playwright-blazor-testing, snapshot-testing |
| 122 | +
|
| 123 | +Quality gates (use when applicable) |
| 124 | +- dotnet-slopwatch: after substantial new/refactor/LLM-authored code |
| 125 | +- crap-analysis: after tests added/changed in complex code |
| 126 | +
|
| 127 | +Specialist agents |
| 128 | +- dotnet-concurrency-specialist, dotnet-performance-analyst, dotnet-benchmark-designer, akka-net-specialist, docfx-specialist |
| 129 | +
|
| 130 | +# C# Semantic Enforcement (csharp-lsp) |
| 131 | +
|
| 132 | +This repository requires semantic analysis for all C# changes. |
| 133 | +
|
| 134 | +Plugin: |
| 135 | +- csharp-lsp @ claude-plugins-official |
| 136 | +
|
| 137 | +### When Mandatory |
| 138 | +
|
| 139 | +Activate `csharp-lsp` when: |
| 140 | +- Modifying or creating *.cs files |
| 141 | +- Changing *.csproj or solution structure |
| 142 | +- Refactoring (rename, move, signature change) |
| 143 | +- Performing cross-file or cross-namespace changes |
| 144 | +- Modifying public APIs or protocol frame types |
| 145 | +
|
| 146 | +### Required Before Commit |
| 147 | +
|
| 148 | +For any C# modification: |
| 149 | +
|
| 150 | +1. Inspect affected types and their references. |
| 151 | +2. Verify no downstream breakage. |
| 152 | +3. Check diagnostics. |
| 153 | +4. Ensure zero compile-time errors remain. |
| 154 | +
|
| 155 | +If C# files were modified and semantic validation was not performed, |
| 156 | +the iteration is considered incomplete. |
| 157 | +
|
| 158 | +Log usage of csharp-lsp in the Flight Recorder. |
| 159 | +
|
| 160 | +## RFC Compliance |
| 161 | +
|
| 162 | +- **HTTP/1.0**: RFC 1945 |
| 163 | +- **HTTP/1.1**: RFC 9112 (message framing) |
| 164 | +- **HTTP/2**: RFC 9113 (protocol), RFC 7541 (HPACK) |
| 165 | +
|
| 166 | +## Dependencies |
| 167 | +
|
| 168 | +- **Akka.Streams** 1.5.60 - Actor-based stream processing |
| 169 | +- **Servus.Akka** 0.3.10 - TCP abstraction layer |
| 170 | +- **.NET 10.0** - Target framework |
0 commit comments