Skip to content

Commit 9ad62e1

Browse files
committed
fix Docs
1 parent f87bbb5 commit 9ad62e1

9 files changed

Lines changed: 419 additions & 118 deletions

File tree

CLAUDE.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,41 @@ TurboHttp is a high-performance HTTP client library for .NET built on Akka.Strea
88

99
## Build Commands
1010

11+
> **Note:** All commands run from the **repository root** (`d:\GIT\Akka.Streams.Http\`).
12+
> `dotnet test --project` paths are relative to `src/` (where `global.json` with MTP runner lives).
13+
> `dotnet restore`/`build`/`run` use full paths from root.
14+
1115
```bash
1216
# Restore and build
1317
dotnet restore ./src/TurboHttp.sln
1418
dotnet build --configuration Release ./src/TurboHttp.sln
1519

16-
# Run all tests
17-
dotnet test ./src/TurboHttp.sln
20+
# Run all tests (includes integration tests — requires network)
21+
dotnet test --project TurboHttp.sln
22+
23+
# Run unit tests only
24+
dotnet test --project TurboHttp.Tests/TurboHttp.Tests.csproj
1825

19-
# Run specific test class (xUnit v3 MTP filternote: args after --)
20-
dotnet test ./src/TurboHttp.Tests/TurboHttp.Tests.csproj -- --filter-class "TurboHttp.Tests.RFC9113.Http2DecoderBasicFrameTests"
26+
# Run specific test class (xUnit v3 direct runner-class flag)
27+
dotnet run --project TurboHttp.Tests/TurboHttp.Tests.csproj -- -class "TurboHttp.Tests.RFC9113.Http2DecoderErrorCodeTests"
2128

2229
# Run specific RFC section (by namespace)
23-
dotnet test ./src/TurboHttp.Tests/TurboHttp.Tests.csproj -- --filter-namespace "TurboHttp.Tests.RFC9113"
30+
dotnet test --project TurboHttp.Tests/TurboHttp.Tests.csproj -- --filter-namespace "TurboHttp.Tests.RFC9113"
2431

2532
# Run integration tests (H10/H11/H2/H3/TLS — requires network)
26-
dotnet test ./src/TurboHttp.IntegrationTests/TurboHttp.IntegrationTests.csproj
33+
dotnet test --project TurboHttp.IntegrationTests/TurboHttp.IntegrationTests.csproj
2734

2835
# Run integration tests for one HTTP version
29-
dotnet test ./src/TurboHttp.IntegrationTests/TurboHttp.IntegrationTests.csproj -- --filter-namespace "TurboHttp.IntegrationTests.H11"
36+
dotnet test --project TurboHttp.IntegrationTests/TurboHttp.IntegrationTests.csproj -- --filter-namespace "TurboHttp.IntegrationTests.H11"
3037

3138
# Run Akka.Streams stage tests
32-
dotnet test ./src/TurboHttp.StreamTests/TurboHttp.StreamTests.csproj
39+
dotnet test --project TurboHttp.StreamTests/TurboHttp.StreamTests.csproj
3340

3441
# Run stage tests for one RFC section
35-
dotnet test ./src/TurboHttp.StreamTests/TurboHttp.StreamTests.csproj -- --filter-namespace "TurboHttp.StreamTests.RFC9113"
42+
dotnet test --project TurboHttp.StreamTests/TurboHttp.StreamTests.csproj -- --filter-namespace "TurboHttp.StreamTests.RFC9113"
3643

3744
# Run benchmarks
38-
dotnet run --configuration Release ./src/TurboHttp.Benchmarks/TurboHttp.Benchmarks.csproj
45+
dotnet run --configuration Release --project TurboHttp.Benchmarks/TurboHttp.Benchmarks.csproj
3946
```
4047

4148
### Documentation Site (requires Node.js 20+)

docs/.vitepress/config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ export default defineConfig({
55
description: 'High-performance HTTP client library for .NET built on Akka.Streams — HTTP/1.0, HTTP/1.1, and HTTP/2 with automatic retries, caching, cookies, and connection pooling.',
66
base: '/',
77
head: [
8-
['link', { rel: 'icon', type: 'image/png', href: '/TurboHttp/logo/icon.png' }],
8+
['link', { rel: 'icon', type: 'image/png', href: '/logo/icon.png' }],
99
],
1010
themeConfig: {
11-
logo: '/logo/logo_small.png',
11+
logo: '/logo/icon.png',
1212
search: {
1313
provider: 'local',
1414
},

docs/architecture/index.md

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,40 @@ Your Request
1515
1616
[Enricher] — applies default headers, base address
1717
18+
[Tracing] — starts an activity span for observability
19+
20+
[Handlers] — runs any custom middleware you registered
21+
22+
[Redirects] — tracks redirect chain; follows on response side
23+
1824
[Cookies] — injects matching cookies from the cookie jar
1925
20-
[Cache] — checks if response is cached; returns immediately if fresh
26+
[Retry] — attaches retry context; re-sends on transient failures
27+
28+
[Expect-Continue] — holds large bodies until server confirms readiness
29+
30+
[Cache] — returns immediately if response is cached and fresh
31+
32+
[Content Encoding] — compresses request body / decompresses response
2133
2234
[Protocol Encoder] — converts to HTTP/1.0, 1.1, 2, or 3 bytes
2335
2436
[Network] — sends over TCP or QUIC
2537
2638
[Protocol Decoder] — parses response bytes
2739
28-
[Decompression] — decompresses gzip/deflate/brotli
40+
[Content Encoding] — decompresses gzip/deflate/brotli
2941
30-
[Cookies] — stores Set-Cookie headers
31-
32-
[Cache] — caches the response if cacheable
42+
[Cache] — stores response if cacheable
3343
3444
[Retry] — re-sends on transient errors or 503/429
3545
46+
[Cookies] — stores Set-Cookie headers
47+
3648
[Redirects] — follows 301-308 automatically
3749
50+
[Tracing] — closes the activity span
51+
3852
Your Response
3953
```
4054

@@ -45,10 +59,10 @@ Each stage does one thing well. Most of the time you don't think about them —
4559
- **Automatic**: Cookies, caching, retries, redirects all work out of the box
4660
- **Efficient**: HTTP/2 and HTTP/3 multiplexing, keep-alive connection reuse, lock-free data movement
4761
- **Correct**: Follows HTTP specifications for freshness, method rewriting, retry idempotency
48-
- **Observable**: See exactly what happens at each stage
62+
- **Observable**: See exactly what happens at each stage via built-in tracing
4963

5064
## Learn More
5165

5266
- [**Pipeline Details**](./pipeline) — All stages and how they interact
5367
- [**Scenarios**](./scenarios) — End-to-end walkthroughs for HTTP/1.0, 1.1, 2, and 3
54-
- [**Connection Pooling**](../guide/connection-pooling) — How connections are reused
68+
- [**Connection Pooling**](../guide/connection-pooling) — How connections are reused

docs/architecture/pipeline.md

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,33 @@ Each `HttpRequestMessage` passes through the following stages before reaching th
1515
| # | Stage | What it does |
1616
|---|-------|--------------|
1717
| 1 | Request Enrichment (`RequestEnricherStage`) | Applies your `BaseAddress`, default HTTP version, and default headers to every request |
18-
| 2 | Cookie Injection (`CookieBidiStage`) | Looks up matching cookies for the target domain and path and adds a `Cookie` header |
19-
| 3 | Cache Lookup (`CacheBidiStage`) | Checks the in-memory cache; on a **cache hit**, returns the cached response immediately — stages 4–5 are skipped entirely |
20-
| 4 | Version Router (`Engine`) | Routes the request to the correct protocol handler based on the requested HTTP version |
21-
| 5 | Protocol Encoder *(per version)* | Serialises the request to bytes and sends it over the network connection |
18+
| 2 | Tracing (`TracingBidiStage`) | Starts an activity span for observability; records request method, URL, timing, and final status code |
19+
| 3 | User Handlers (`HandlerBidiStage`) | Runs any custom middleware you registered — zero or more, applied outermost-first |
20+
| 4 | Redirect (`RedirectBidiStage`) | Tracks the redirect chain; on a `301``308` response, re-enters the pipeline at the Cookie stage so new-URL cookies are injected |
21+
| 5 | Cookie Injection (`CookieBidiStage`) | Looks up matching cookies for the target domain and path and adds a `Cookie` header |
22+
| 6 | Retry (`RetryBidiStage`) | On the request side, attaches retry context; on a transient failure, re-enters below the Cookie stage (same URL, cookies already set) |
23+
| 7 | Expect-Continue (`ExpectContinueBidiStage`) | For requests with large bodies, sends `Expect: 100-continue` and holds the body until the server confirms it will accept it |
24+
| 8 | Cache Lookup (`CacheBidiStage`) | Checks the in-memory cache; on a **cache hit**, returns the cached response immediately — stages 9–10 are skipped entirely |
25+
| 9 | Content Encoding (`ContentEncodingBidiStage`) | Compresses the request body if a compression policy is configured; on the response side, transparently decompresses `gzip`, `deflate`, or Brotli |
26+
| 10 | Version Router (`Engine`) | Routes the request to the correct protocol handler based on the requested HTTP version |
27+
| 11 | Protocol Encoder *(per version)* | Serialises the request to bytes and sends it over the network connection |
2228

2329
---
2430

2531
## Response Chain (right to left / bottom to top)
2632

27-
After bytes return from TCP, the response passes through these stages:
33+
After bytes return from the network, the response passes back through the stages in reverse order:
2834

2935
| # | Stage | What it does |
3036
|---|-------|--------------|
3137
| 1 | Protocol Decoder *(per version)* | Parses raw bytes into an `HttpResponseMessage` and matches it to the original request |
32-
| 2 | Decompression (`DecompressionBidiStage`) | Transparently decompresses `gzip`, `deflate`, or Brotli response bodies |
33-
| 3 | Cookie Storage (`CookieBidiStage`) | Reads `Set-Cookie` headers and stores cookies for future requests |
34-
| 4 | Cache Storage (`CacheBidiStage`) | Saves cacheable responses so future matching requests can be served from memory |
38+
| 2 | Content Encoding (`ContentEncodingBidiStage`) | Transparently decompresses `gzip`, `deflate`, or Brotli response bodies |
39+
| 3 | Cache Storage (`CacheBidiStage`) | Saves cacheable responses so future matching requests can be served from memory |
40+
| 4 | Expect-Continue (`ExpectContinueBidiStage`) | Processes `100 Continue` responses and unblocks the request body when the server is ready |
3541
| 5 | Automatic Retry (`RetryBidiStage`) | Re-sends safe (idempotent) requests on transient errors or `503`/`429` responses; respects `Retry-After` delays |
36-
| 6 | Redirect Following (`RedirectBidiStage`) | Follows `301``308` redirects automatically; rewrites the HTTP method where needed; detects loops and blocks HTTPS→HTTP downgrades |
42+
| 6 | Cookie Storage (`CookieBidiStage`) | Reads `Set-Cookie` headers and stores cookies for future requests |
43+
| 7 | Redirect Following (`RedirectBidiStage`) | Follows `301``308` redirects automatically; rewrites the HTTP method where needed; detects loops and blocks HTTPS→HTTP downgrades |
44+
| 8 | Tracing (`TracingBidiStage`) | Closes the activity span, recording the final status code and any errors |
3745

3846
---
3947

@@ -53,11 +61,17 @@ After each HTTP/1.1 response, a signal is sent back to the connection layer indi
5361

5462
This loop is invisible to the caller — the `Engine` and higher layers see only a continuous stream of `HttpResponseMessage` objects.
5563

56-
### 3. Retry / Redirect Re-entry (red)
64+
### 3. Redirect Re-entry
5765

58-
When `RetryBidiStage` decides a request should be retried, or when `RedirectBidiStage` needs to follow a redirect, the new `HttpRequestMessage` is fed back into the **front of the pipeline** (before `RequestEnricherStage`). This ensures that retry enrichment, cookie injection, and cache lookup all apply again on the new attempt.
66+
When `RedirectBidiStage` needs to follow a redirect, the new `HttpRequestMessage` re-enters the pipeline at the **Cookie stage** — not at the very beginning. This ensures cookie injection applies for the new URL while skipping the initial enrichment step (default headers are already applied). A redirect hop limit prevents infinite loops.
5967

60-
A maximum retry count and redirect hop limit prevent infinite loops.
68+
### 4. Retry Re-entry
69+
70+
When `RetryBidiStage` decides a request should be retried, it re-enters the pipeline at the **Expect-Continue stage** — below Cookie injection, since the URL hasn't changed and cookies are already set. A maximum retry count prevents infinite loops.
71+
72+
### 5. QPACK Table Sync (HTTP/3 only)
73+
74+
HTTP/3 uses QPACK for header compression. The server sends decoder table updates on a dedicated QUIC stream; `QpackDecoderFeedbackStage` forwards these updates back to `Http30Request2FrameStage` to keep the encoder and decoder tables in sync.
6175

6276
---
6377

0 commit comments

Comments
 (0)