From 12afcc974d48ce6e8b8d79cc64baaae08f9126ea Mon Sep 17 00:00:00 2001 From: Diogo Martins Date: Sat, 14 Feb 2026 11:53:14 +0000 Subject: [PATCH] Add AI Contribution and RFC Dashboard --- AGENTS.md | 295 +++++++++++++++++ CHANGELOG.md | 11 +- docs/assets/css/custom.css | 6 + docs/content/_index.md | 11 +- docs/content/add-a-test.md | 170 ++++++++++ docs/content/add-with-ai-agent.md | 44 +++ docs/content/docs/_index.md | 1 + docs/content/docs/baseline.md | 2 +- docs/content/docs/rfc-basics.md | 2 +- .../content/docs/rfc-requirement-dashboard.md | 309 ++++++++++++++++++ docs/hugo.yaml | 13 +- 11 files changed, 857 insertions(+), 7 deletions(-) create mode 100644 AGENTS.md create mode 100644 docs/content/add-a-test.md create mode 100644 docs/content/add-with-ai-agent.md create mode 100644 docs/content/docs/rfc-requirement-dashboard.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..5da300c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,295 @@ +# Http11Probe — AI Agent Contribution Guide + +This file is designed for LLM/AI agent consumption. It contains precise, unambiguous instructions for adding a new test or a new framework to the Http11Probe platform. + +## Project overview + +Http11Probe is an HTTP/1.1 compliance and security tester. It sends raw TCP requests to servers and validates responses against RFC 9110/9112. The codebase is C# / .NET 10. Documentation is a Hugo + Hextra static site under `docs/`. + +--- + +## TASK A: Add a new test + +Adding a test requires changes to **4 locations** (sometimes 3 if URL mapping is automatic). + +### Step 1 — Add the test case to the suite file + +Choose the correct suite file based on category: + +| Category | File path | +|----------|-----------| +| Compliance | `src/Http11Probe/TestCases/Suites/ComplianceSuite.cs` | +| Smuggling | `src/Http11Probe/TestCases/Suites/SmugglingSuite.cs` | +| Malformed Input | `src/Http11Probe/TestCases/Suites/MalformedInputSuite.cs` | +| Normalization | `src/Http11Probe/TestCases/Suites/NormalizationSuite.cs` | + +Append a `yield return new TestCase { ... };` inside the `GetTestCases()` method. Here is the full schema: + +```csharp +yield return new TestCase +{ + // REQUIRED fields + Id = "COMP-EXAMPLE", // Unique ID. Prefix conventions below. + Description = "What this test checks", // One-line human description. + Category = TestCategory.Compliance, // Compliance | Smuggling | MalformedInput | Normalization + PayloadFactory = ctx => MakeRequest( // Builds the raw HTTP bytes to send. + $"GET / HTTP/1.1\r\nHost: {ctx.HostHeader}\r\n\r\n" + ), + Expected = new ExpectedBehavior // How to validate the response. See below. + { + ExpectedStatus = StatusCodeRange.Exact(400), + }, + + // OPTIONAL fields + RfcReference = "RFC 9112 §5.1", // Use § not "Section". Omit if no RFC applies. + Scored = true, // Default true. Set false for MAY/informational tests. + AllowConnectionClose = false, // On Expected. See validation rules below. + FollowUpPayloadFactory = ctx => ..., // Second request on same connection (pipeline tests). + RequiresConnectionReuse = false, // True if FollowUpPayloadFactory needs same TCP connection. + BehavioralAnalyzer = (response) => ..., // Optional Func for analysis notes. +}; +``` + +**Test ID prefix conventions:** + +| Prefix | Suite | +|--------|-------| +| `COMP-` | Compliance | +| `SMUG-` | Smuggling | +| `MAL-` | Malformed Input | +| `NORM-` | Normalization | +| `RFC9112-X.X-` or `RFC9110-X.X-` | Compliance (maps directly to an RFC section) | + +**Validation patterns — choose ONE:** + +Pattern 1 — Exact status, no alternatives: +```csharp +Expected = new ExpectedBehavior +{ + ExpectedStatus = StatusCodeRange.Exact(400), +} +``` +Use for strict MUST-400 requirements (e.g. SP-BEFORE-COLON, MISSING-HOST, DUPLICATE-HOST, OBS-FOLD, CR-ONLY). + +Pattern 2 — Status with connection close as alternative: +```csharp +Expected = new ExpectedBehavior +{ + ExpectedStatus = StatusCodeRange.Exact(400), + AllowConnectionClose = true, +} +``` +Use when close is acceptable instead of a status code. + +Pattern 3 — Custom validator (takes priority over ExpectedStatus): +```csharp +Expected = new ExpectedBehavior +{ + CustomValidator = (response, state) => + { + if (state == ConnectionState.ClosedByServer && response is null) return TestVerdict.Pass; + if (response is null) return TestVerdict.Fail; + if (response.StatusCode == 400) return TestVerdict.Pass; + if (response.StatusCode >= 200 && response.StatusCode < 300) return TestVerdict.Warn; + return TestVerdict.Fail; + }, + Description = "400 or close = pass, 2xx = warn", +} +``` +Use for pass/warn/fail logic, timeout acceptance, or multi-outcome tests. + +**Available StatusCodeRange factories:** +- `StatusCodeRange.Exact(int code)` — single status code +- `StatusCodeRange.Range(int start, int end)` — inclusive range +- `StatusCodeRange.Range2xx` — 200-299 +- `StatusCodeRange.Range4xx` — 400-499 +- `StatusCodeRange.Range4xxOr5xx` — 400-599 + +**Available TestVerdict values:** `Pass`, `Fail`, `Warn`, `Skip`, `Error` + +**Available ConnectionState values:** `Open`, `ClosedByServer`, `TimedOut`, `Error` + +**Helper method available in all suites:** +```csharp +private static byte[] MakeRequest(string request) => Encoding.ASCII.GetBytes(request); +``` + +**Critical rules:** +- NEVER set `AllowConnectionClose = true` for MUST-400 requirements where the RFC explicitly says "respond with 400". +- Set `Scored = false` only for MAY-level or purely informational tests. +- Always use `ctx.HostHeader` (not a hardcoded host) in payloads. +- Tests are auto-discovered — no registration step needed. The `GetTestCases()` yield return is sufficient. + +### Step 2 — Add docs URL mapping (conditional) + +**File:** `src/Http11Probe.Cli/Reporting/DocsUrlMap.cs` + +This step is **only needed** for `COMP-*` and `RFC*` prefixed tests. The following prefixes are auto-mapped: +- `SMUG-XYZ` → `smuggling/xyz` (lowercased) +- `MAL-XYZ` → `malformed-input/xyz` (lowercased) +- `NORM-XYZ` → `normalization/xyz` (lowercased) + +For compliance tests, add an entry to the `ComplianceSlugs` dictionary: +```csharp +["COMP-EXAMPLE"] = "headers/example", +``` + +If the doc filename doesn't match the auto-mapping convention, add to `SpecialSlugs` instead: +```csharp +["MAL-CHUNK-EXT-64K"] = "malformed-input/chunk-extension-long", +``` + +### Step 3 — Create the documentation page + +**File:** `docs/content/docs/{category-slug}/{test-slug}.md` + +Category slug mapping: + +| Category | Slug | +|----------|------| +| Compliance (line endings) | `line-endings` | +| Compliance (request line) | `request-line` | +| Compliance (headers) | `headers` | +| Compliance (host header) | `host-header` | +| Compliance (content-length) | `content-length` | +| Compliance (body) | `body` | +| Compliance (upgrade) | `upgrade` | +| Smuggling | `smuggling` | +| Malformed Input | `malformed-input` | +| Normalization | `normalization` | + +Use this exact template: + +```markdown +--- +title: "EXAMPLE" +description: "EXAMPLE test documentation" +weight: 1 +--- + +| | | +|---|---| +| **Test ID** | `COMP-EXAMPLE` | +| **Category** | Compliance | +| **RFC** | [RFC 9112 §X.X](https://www.rfc-editor.org/rfc/rfc9112#section-X.X) | +| **Requirement** | MUST | +| **Expected** | `400` or close | + +## What it sends + +A request with [description of the non-conforming element]. + +\```http +GET / HTTP/1.1\r\n +Host: localhost:8080\r\n +[malformed element]\r\n +\r\n +\``` + +## What the RFC says + +> "Exact quote from the RFC with the MUST/SHOULD/MAY keyword." -- RFC 9112 Section X.X + +Explanation of what the quote means for this test. + +## Why it matters + +Security and compatibility implications. Why this matters for real-world deployments. + +## Sources + +- [RFC 9112 §X.X](https://www.rfc-editor.org/rfc/rfc9112#section-X.X) +``` + +**Requirement field values:** `MUST`, `SHOULD`, `MAY`, `"ought to"`, `Implicit MUST (grammar violation)`, `Unscored`, or a descriptive phrase like `MUST reject or replace with SP`. + +### Step 4 — Add a card to the category index + +**File:** `docs/content/docs/{category-slug}/_index.md` + +Find the `{{}}` block and add a new card entry. Place scored tests before unscored tests. + +``` +{{}} +``` + +The `link` value is the filename without `.md`. + +### Verification checklist + +After making all changes: + +1. `dotnet build Http11Probe.slnx -c Release` — must compile without errors. +2. The new test ID appears in the output of `dotnet run --project src/Http11Probe.Cli -- --host localhost --port 8080`. +3. Hugo docs render: `cd docs && hugo server` — the new page is accessible and linked from its category index. + +--- + +## TASK B: Add a new framework + +Adding a framework requires creating **3 files** in a new directory. No existing files need modification. + +### Step 1 — Create the server directory + +Create a new directory: `src/Servers/YourServer/` + +### Step 2 — Implement the server + +Your server MUST listen on **port 8080** and implement these endpoints: + +| Endpoint | Method | Behavior | +|----------|--------|----------| +| `/` | `GET` | Return `200 OK` | +| `/` | `HEAD` | Return `200 OK` with no body | +| `/` | `POST` | Read the full request body and return it in the response body | +| `/` | `OPTIONS` | Return `200 OK` | +| `/echo` | `POST` | Return all received request headers in the response body, one per line as `Name: Value` | + +The `/echo` endpoint is critical for normalization tests. It must echo back all headers the server received, preserving the names as the server internally represents them. + +Example `/echo` response body: +``` +Host: localhost:8080 +Content-Length: 11 +Content-Type: text/plain +``` + +### Step 3 — Add a Dockerfile + +Create `src/Servers/YourServer/Dockerfile` that builds and runs the server. + +Key requirements: +- The container runs with `--network host`, so bind to `0.0.0.0:8080`. +- Use `ENTRYPOINT` (not `CMD`) for the server process. +- The Dockerfile build context is the repository root, so paths like `COPY src/Servers/YourServer/...` are correct. + +Example: +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir flask +COPY src/Servers/YourServer/app.py . +ENTRYPOINT ["python3", "app.py", "8080"] +``` + +### Step 4 — Add probe.json + +Create `src/Servers/YourServer/probe.json` with exactly one field: + +```json +{"name": "Your Server Display Name"} +``` + +This name appears in the leaderboard and PR comments. + +### Verification checklist + +1. Build the Docker image: `docker build -f src/Servers/YourServer/Dockerfile -t yourserver .` +2. Run: `docker run --network host yourserver` +3. Verify endpoints: + - `curl http://localhost:8080/` returns 200 + - `curl -X POST -d "hello" http://localhost:8080/` returns "hello" + - `curl -X POST -d "test" http://localhost:8080/echo` returns headers +4. Run the probe: `dotnet run --project src/Http11Probe.Cli -- --host localhost --port 8080` + +No changes to CI workflows, configs, or other files are needed. The pipeline auto-discovers servers from `src/Servers/*/probe.json`. diff --git a/CHANGELOG.md b/CHANGELOG.md index 30ead82..483a890 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,15 @@ All notable changes to Http11Probe are documented in this file. -## [Unreleased] +## [2026-02-14] ### Added +- **RFC Requirement Dashboard** — all 148 tests classified by RFC 2119 level (MUST/SHOULD/MAY/"ought to"/Unscored/N/A) with exact RFC quotes proving each classification (`docs/content/docs/rfc-requirement-dashboard.md`) +- **Add a Test guide** — step-by-step documentation for contributing new tests to the platform (`docs/content/add-a-test.md`) +- **AI Agent contribution guide** — machine-readable `AGENTS.md` at repo root with precise instructions for LLM agents to add tests or frameworks (`docs/content/add-with-ai-agent.md`) +- **Contribute menu** — top nav "Add a Framework" replaced with a "Contribute" dropdown containing Add a Framework, Add a Test, and Add with AI Agent +- **Landing page cards** — RFC Requirement Dashboard card in hero section; Add a Test and Add with AI Agent cards in Contribute section +- **Glossary card** — RFC Requirement Dashboard linked from the glossary index page - **Server configuration pages** — per-server docs pages showing Dockerfile, source code, and config files for all 36 tested servers (`docs/content/servers/`) - **Clickable server names** — server names in the probe results table and summary bar chart now link to their configuration page - **Sticky first column** — server name column stays pinned to the left edge while scrolling horizontally through result tables @@ -33,6 +39,9 @@ All notable changes to Http11Probe are documented in this file. - **Stronger sticky shadow on mobile** — increased shadow intensity for the pinned server name column - **Scrollable tooltips** — hover tooltips are now interactive and scrollable for large payloads (removed `pointer-events:none`, increased `max-height` to `60vh`) - **Larger click modal** — expanded from `max-width:700px` to `90vw` and `max-height` from `80vh` to `85vh` to better accommodate large request/response data +- **Landing page section rename** — "Add Your Framework" heading renamed to "Contribute to the Project" with updated copy emphasizing community contributions +- **Uniform card sizing** — CSS rule forces all home page card grids to `repeat(2, 1fr)` so every card is the same width +- **Sidebar reordering** — RFC Requirement Dashboard at weight 2 (after Understanding HTTP), RFC Basics bumped to 3, Baseline to 4 - **Kestrel HEAD/OPTIONS support** — added explicit HEAD and OPTIONS endpoint handlers to ASP.NET Minimal server so smuggling tests evaluate correctly instead of returning 405 - **Add a Framework docs** — documented HEAD and OPTIONS as required endpoints - Raw request capture now includes truncation metadata when payload exceeds 8,192 bytes (`TestRunner.cs`) diff --git a/docs/assets/css/custom.css b/docs/assets/css/custom.css index 92d72e7..b84bb3b 100644 --- a/docs/assets/css/custom.css +++ b/docs/assets/css/custom.css @@ -45,6 +45,12 @@ html.dark .hextra-content { background: transparent !important; } +/* ── Home page: uniform card grid ────────────────────────────── */ + +.hextra-home-body .hextra-cards { + grid-template-columns: repeat(2, 1fr) !important; +} + /* ── Cards ───────────────────────────────────────────────────── */ .hextra-card { diff --git a/docs/content/_index.md b/docs/content/_index.md index 0ba785d..c6a6e70 100644 --- a/docs/content/_index.md +++ b/docs/content/_index.md @@ -24,6 +24,7 @@ layout: hextra-home {{< cards >}} {{< card link="probe-results" title="Leaderboard" subtitle="See which frameworks pass the most tests, ranked from best to worst compliance." icon="chart-bar" >}} + {{< card link="docs/rfc-requirement-dashboard" title="RFC Requirement Dashboard" subtitle="All 148 tests classified by RFC 2119 level (MUST/SHOULD/MAY)." icon="document-search" >}} {{< /cards >}}
@@ -45,15 +46,19 @@ Http11Probe sends a suite of crafted HTTP requests to each server and checks whe
-

Add Your Framework

+

Contribute to the Project

-Http11Probe is designed so anyone can contribute their HTTP server and get compliance results without touching the test infrastructure. Just add a Dockerfile, a one-line `probe.json`, and open a PR. +Http11Probe is open source and built for contributions. Add your HTTP server to the leaderboard, or write new test cases to expand coverage. + +Every new framework added makes the comparison more useful for the entire community, and every new test strengthens the compliance bar for all servers on the platform. If you've found an edge case that isn't covered, or you maintain a framework that isn't listed yet, your contribution directly improves HTTP security and interoperability for everyone.
{{< cards >}} - {{< card link="add-a-framework" title="Get Started" subtitle="Three steps to add your framework — Dockerfile, probe.json, and open a PR." icon="plus-circle" >}} + {{< card link="add-a-framework" title="Add a Framework" subtitle="Three steps to add your framework — Dockerfile, probe.json, and open a PR." icon="plus-circle" >}} + {{< card link="add-a-test" title="Add a Test" subtitle="How to define a new test case, write its documentation, and wire it into the platform." icon="beaker" >}} + {{< card link="add-with-ai-agent" title="Add with AI Agent" subtitle="Use an AI coding agent to add a test or framework using the machine-readable AGENTS.md guide." icon="chip" >}} {{< /cards >}} diff --git a/docs/content/add-a-test.md b/docs/content/add-a-test.md new file mode 100644 index 0000000..031561e --- /dev/null +++ b/docs/content/add-a-test.md @@ -0,0 +1,170 @@ +--- +title: Add a Test +--- + +A step-by-step guide to adding a new test to Http11Probe. Every test touches four places: the suite file, the docs URL map (sometimes), a documentation page, and the category index. + +## 1. Define the test case + +Pick the suite that matches your test's category and add a `yield return new TestCase` block. + +| Category | File | +|----------|------| +| Compliance | `src/Http11Probe/TestCases/Suites/ComplianceSuite.cs` | +| Smuggling | `src/Http11Probe/TestCases/Suites/SmugglingSuite.cs` | +| Malformed Input | `src/Http11Probe/TestCases/Suites/MalformedInputSuite.cs` | +| Normalization | `src/Http11Probe/TestCases/Suites/NormalizationSuite.cs` | + +```csharp +yield return new TestCase +{ + Id = "COMP-MY-TEST", + Description = "Description of what the test checks", + Category = TestCategory.Compliance, + RfcReference = "RFC 9112 §X.X", + + PayloadFactory = ctx => MakeRequest( + $"GET / HTTP/1.1\r\nHost: {ctx.HostHeader}\r\n\r\n" + ), + + Expected = new ExpectedBehavior + { + ExpectedStatus = StatusCodeRange.Exact(400), + AllowConnectionClose = true, + }, + + Scored = true, +}; +``` + +### Test ID naming + +| Prefix | Suite | +|--------|-------| +| `COMP-` | Compliance | +| `SMUG-` | Smuggling | +| `MAL-` | Malformed Input | +| `NORM-` | Normalization | +| `RFC9112-...` or `RFC9110-...` | Compliance (when the test maps directly to a specific RFC section) | + +### Validation options + +**Simple status check:** + +```csharp +Expected = new ExpectedBehavior +{ + ExpectedStatus = StatusCodeRange.Exact(400), +} +``` + +**Allow connection close as alternative:** + +```csharp +Expected = new ExpectedBehavior +{ + ExpectedStatus = StatusCodeRange.Exact(400), + AllowConnectionClose = true, +} +``` + +**Custom validator** (takes priority over `ExpectedStatus`): + +```csharp +Expected = new ExpectedBehavior +{ + CustomValidator = (response, state) => + { + if (response?.StatusCode == 400) return TestVerdict.Pass; + if (response?.StatusCode >= 200 && response.StatusCode < 300) + return TestVerdict.Warn; + return TestVerdict.Fail; + }, + Description = "400 = pass, 2xx = warn" +} +``` + +### Key conventions + +- Use `Exact(400)` with **no** `AllowConnectionClose` for strict MUST-400 requirements (SP-BEFORE-COLON, MISSING-HOST, DUPLICATE-HOST, OBS-FOLD, CR-ONLY). +- Set `AllowConnectionClose = true` only when connection close is an acceptable alternative to a status code. +- Set `Scored = false` for MAY-level or informational tests. +- Use `"RFC 9112 §5.1"` format for `RfcReference` (section sign, not "Section"). + +## 2. Add a docs URL mapping (if needed) + +**File:** `src/Http11Probe.Cli/Reporting/DocsUrlMap.cs` + +Tests prefixed with `SMUG-`, `MAL-`, or `NORM-` are auto-mapped to their doc URL based on the ID. For example, `SMUG-CL-TE-BOTH` maps to `smuggling/cl-te-both`. + +For `COMP-*` or `RFC*` prefixed tests, add an entry to the `ComplianceSlugs` dictionary: + +```csharp +["COMP-MY-TEST"] = "headers/my-test", +``` + +If the slug doesn't follow the standard pattern (e.g. the filename differs from the ID), add it to `SpecialSlugs` instead. + +## 3. Create the documentation page + +**File:** `docs/content/docs/{category}/{test-slug}.md` + +Use this template: + +```markdown +--- +title: "MY-TEST" +description: "MY-TEST test documentation" +weight: 1 +--- + +| | | +|---|---| +| **Test ID** | `COMP-MY-TEST` | +| **Category** | Compliance | +| **RFC** | [RFC 9112 §X.X](https://www.rfc-editor.org/rfc/rfc9112#section-X.X) | +| **Requirement** | MUST | +| **Expected** | `400` or close | + +## What it sends + +Description of the request and what makes it non-conforming. + +## What the RFC says + +> "Exact quote from the RFC." -- RFC 9112 Section X.X + +## Why it matters + +Security and compatibility implications. + +## Sources + +- [RFC 9112 §X.X](https://www.rfc-editor.org/rfc/rfc9112#section-X.X) +``` + +## 4. Add a card to the category index + +**File:** `docs/content/docs/{category}/_index.md` + +Add a card entry in the appropriate section (scored or unscored): + +``` +{{}} +``` + +## 5. Verify + +Build and run the probe locally: + +```bash +dotnet build Http11Probe.slnx -c Release +dotnet run --project src/Http11Probe.Cli -- --host localhost --port 8080 +``` + +Check that: +- Your test appears in the JSON output with the correct ID +- The verdict makes sense against a known server +- The documentation page renders correctly with `hugo server` in `docs/` + +No changes are needed in the CI workflow -- new tests are discovered automatically. diff --git a/docs/content/add-with-ai-agent.md b/docs/content/add-with-ai-agent.md new file mode 100644 index 0000000..05f8987 --- /dev/null +++ b/docs/content/add-with-ai-agent.md @@ -0,0 +1,44 @@ +--- +title: Add with AI Agent +--- + +Use an AI coding agent (Claude Code, Cursor, Copilot, etc.) to add a new test or framework to Http11Probe. The repository includes a machine-readable contribution guide at [`AGENTS.md`](https://github.com/MDA2AV/Http11Probe/blob/main/AGENTS.md) designed specifically for LLM consumption. + +## How to use it + +Point your AI agent at the repository and reference the `AGENTS.md` file. It contains precise, unambiguous instructions for both tasks: + +- **Task A** — Add a new test (4 steps: suite file, docs URL map, documentation page, category index card) +- **Task B** — Add a new framework (3 files: server implementation, Dockerfile, probe.json) + +## Example prompts + +### Adding a test + +> Read AGENTS.md, then add a new compliance test that checks whether the server rejects requests with a space before the colon in a header field name. The RFC reference is RFC 9112 §5.1. + +### Adding a framework + +> Read AGENTS.md, then add a new Express.js server to the platform. Use Node 22 and make sure all five endpoints are implemented. + +## What the agent will do + +For a new **test**, the agent will: + +1. Add a `yield return new TestCase { ... }` block to the correct suite file +2. Add a docs URL mapping entry (if the test is `COMP-*` or `RFC*` prefixed) +3. Create a documentation page under `docs/content/docs/{category}/` +4. Add a card to the category index page + +For a new **framework**, the agent will: + +1. Create a server directory under `src/Servers/` +2. Implement the server with all required endpoints (GET, HEAD, POST, OPTIONS on `/` and POST on `/echo`) +3. Write a Dockerfile that builds and runs the server on port 8080 +4. Add a `probe.json` with the display name + +## Tips + +- The `AGENTS.md` file includes verification checklists — make sure the agent runs them before submitting +- No changes to CI workflows are needed for either task; tests and servers are auto-discovered +- For tests, the agent should check the RFC to determine the correct requirement level (MUST/SHOULD/MAY) and validation pattern diff --git a/docs/content/docs/_index.md b/docs/content/docs/_index.md index d3df5b5..32f2f2d 100644 --- a/docs/content/docs/_index.md +++ b/docs/content/docs/_index.md @@ -10,6 +10,7 @@ Reference documentation for every test in Http11Probe, organized by topic. Each {{< cards >}} {{< card link="http-overview" title="Understanding HTTP" subtitle="What HTTP is, how HTTP/1.1 works at the wire level, its history from 0.9 to 3, and alternatives." icon="globe-alt" >}} + {{< card link="rfc-requirement-dashboard" title="RFC Requirement Dashboard" subtitle="All 148 tests classified by RFC 2119 level (MUST/SHOULD/MAY)." icon="document-search" >}} {{< card link="rfc-basics" title="RFC Basics" subtitle="What RFCs are, how to read requirement levels (MUST/SHOULD/MAY), and which RFCs define HTTP/1.1." icon="book-open" >}} {{< card link="baseline" title="Baseline" subtitle="Sanity request used to confirm the target is reachable before running negative tests." icon="check-circle" >}} {{< card link="line-endings" title="Line Endings" subtitle="CRLF requirements, bare LF handling, and bare CR rejection per RFC 9112 Section 2.2." icon="code" >}} diff --git a/docs/content/docs/baseline.md b/docs/content/docs/baseline.md index d21af77..6380453 100644 --- a/docs/content/docs/baseline.md +++ b/docs/content/docs/baseline.md @@ -1,7 +1,7 @@ --- title: "BASELINE" description: "BASELINE test documentation" -weight: 3 +weight: 4 --- | | | diff --git a/docs/content/docs/rfc-basics.md b/docs/content/docs/rfc-basics.md index 5e272ee..0fc338a 100644 --- a/docs/content/docs/rfc-basics.md +++ b/docs/content/docs/rfc-basics.md @@ -1,7 +1,7 @@ --- title: RFC Basics description: "RFC Basics — Http11Probe documentation" -weight: 2 +weight: 3 --- ## What is an RFC? diff --git a/docs/content/docs/rfc-requirement-dashboard.md b/docs/content/docs/rfc-requirement-dashboard.md new file mode 100644 index 0000000..30d786b --- /dev/null +++ b/docs/content/docs/rfc-requirement-dashboard.md @@ -0,0 +1,309 @@ +--- +title: "RFC Requirement Dashboard" +description: "Complete RFC 2119 requirement-level analysis for all 148 Http11Probe tests" +weight: 2 +breadcrumbs: false +--- + +This dashboard classifies every Http11Probe test by its [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) requirement level (**MUST**, **SHOULD**, **MAY**, **"ought to"**), with the exact RFC quote that proves it. Tests are grouped by requirement level, then by suite. + +## Summary + +| Requirement Level | Count | Meaning (RFC 2119) | +|---|---|---| +| **MUST** | 84 | Absolute requirement — no compliant implementation may deviate | +| **SHOULD** | 24 | Recommended — valid exceptions exist but must be understood | +| **MAY** | 10 | Truly optional — either behavior is fully compliant | +| **"ought to"** | 1 | Weaker than SHOULD — recommended but not normative | +| **Unscored** | 18 | Informational — no pass/fail judgement | +| **N/A** | 11 | Best-practice / no single RFC verb applies | + +**Total: 148 tests** + +--- + +## MUST-Level Requirements (84 tests) + +These tests enforce absolute RFC requirements. A compliant server has no discretion — it **MUST** behave as specified. + +### MUST — Reject with 400 (No Alternatives) + +These are the strictest tests: the RFC mandates exactly `400 (Bad Request)`. Connection close alone does **not** satisfy the requirement. + +| # | Test ID | Suite | RFC | RFC Quote | +|---|---------|-------|-----|-----------| +| 1 | `RFC9110-5.6.2-SP-BEFORE-COLON` | Compliance | [RFC 9112 §5.1](https://www.rfc-editor.org/rfc/rfc9112#section-5) | "A server **MUST** reject, with a response status code of 400 (Bad Request), any received request message that contains whitespace between a header field name and colon." | +| 2 | `RFC9112-5.1-OBS-FOLD` | Compliance | [RFC 9112 §5.2](https://www.rfc-editor.org/rfc/rfc9112#section-5.2) | "A server that receives an obs-fold in a request message that is not within a 'message/http' container **MUST** either reject the message by sending a 400 (Bad Request)... or replace each received obs-fold with one or more SP octets." | +| 3 | `RFC9112-7.1-MISSING-HOST` | Compliance | [RFC 9112 §3.2](https://www.rfc-editor.org/rfc/rfc9112#section-3.2) | "A server **MUST** respond with a 400 (Bad Request) status code to any HTTP/1.1 request message that lacks a Host header field and to any request message that contains more than one Host header field line or a Host header field with an invalid field value." | +| 4 | `RFC9110-5.4-DUPLICATE-HOST` | Compliance | [RFC 9112 §3.2](https://www.rfc-editor.org/rfc/rfc9112#section-3.2) | "A server **MUST** respond with a 400 (Bad Request) status code to any... request message that contains more than one Host header field line or a Host header field with an invalid field value." | +| 5 | `COMP-DUPLICATE-HOST-SAME` | Compliance | [RFC 9112 §3.2](https://www.rfc-editor.org/rfc/rfc9112#section-3.2) | "A server **MUST** respond with a 400 (Bad Request) status code to any... request message that contains more than one Host header field line..." (applies even when both values are identical) | +| 6 | `RFC9112-3-CR-ONLY-LINE-ENDING` | Compliance | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | "A recipient of such a bare CR **MUST** consider that element to be invalid or replace each bare CR with SP before processing the element or forwarding the message." | + +### MUST — Reject (400 or Connection Close Acceptable) + +The RFC requires rejection, but the mechanism (400 status or connection close) has some flexibility. + +| # | Test ID | Suite | RFC | RFC Quote | +|---|---------|-------|-----|-----------| +| 7 | `RFC9112-5-EMPTY-HEADER-NAME` | Compliance | [RFC 9112 §5](https://www.rfc-editor.org/rfc/rfc9112#section-5) | Grammar: `field-name = token`, `token = 1*tchar`. An empty field name violates 1*tchar (requires at least one character). | +| 8 | `RFC9112-5-INVALID-HEADER-NAME` | Compliance | [RFC 9112 §5](https://www.rfc-editor.org/rfc/rfc9112#section-5) | Grammar: `token = 1*tchar`, `tchar = "!" / "#" / ...`. Brackets are not in the tchar set — implicit **MUST** reject. | +| 9 | `RFC9112-5-HEADER-NO-COLON` | Compliance | [RFC 9112 §5](https://www.rfc-editor.org/rfc/rfc9112#section-5) | Grammar: `field-line = field-name ":" OWS field-value OWS`. The colon is mandatory — implicit **MUST** reject. | +| 10 | `COMP-WHITESPACE-BEFORE-HEADERS` | Compliance | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | "A recipient that receives whitespace between the start-line and the first header field **MUST** either reject the message as invalid or consume each whitespace-preceded line without further processing." | +| 11 | `RFC9112-3-MISSING-TARGET` | Compliance | [RFC 9112 §3](https://www.rfc-editor.org/rfc/rfc9112#section-3) | Grammar: `request-line = method SP request-target SP HTTP-version`. Missing target violates mandatory grammar — implicit **MUST**. | +| 12 | `COMP-ASTERISK-WITH-GET` | Compliance | [RFC 9112 §3.2.4](https://www.rfc-editor.org/rfc/rfc9112#section-3.2.4) | "If a proxy receives an OPTIONS request with an absolute-form of request-target in which the URI has an empty path and no query component, then the last proxy on the request chain **MUST** send a request-target of '*' when it forwards the request to the indicated origin server." Only OPTIONS may use asterisk-form. | +| 13 | `COMP-HOST-WITH-USERINFO` | Compliance | [RFC 9112 §3.2](https://www.rfc-editor.org/rfc/rfc9112#section-3.2) | "A server **MUST** respond with a 400 (Bad Request)... to any request message that contains... a Host header field with an invalid field value." (userinfo component is not valid in Host) | +| 14 | `COMP-HOST-WITH-PATH` | Compliance | [RFC 9112 §3.2](https://www.rfc-editor.org/rfc/rfc9112#section-3.2) | "A server **MUST** respond with a 400 (Bad Request)... to any request message that contains... a Host header field with an invalid field value." (path component is not valid in Host) | +| 15 | `COMP-HOST-EMPTY-VALUE` | Compliance | [RFC 9112 §3.2](https://www.rfc-editor.org/rfc/rfc9112#section-3.2) | "A server **MUST** respond with a 400 (Bad Request)... to any request message that contains... a Host header field with an invalid field value." | +| 16 | `COMP-VERSION-MISSING-MINOR` | Compliance | [RFC 9112 §2.3](https://www.rfc-editor.org/rfc/rfc9112#section-2.3) | Grammar: `HTTP-version = HTTP-name "/" DIGIT "." DIGIT`. "HTTP/1" has no minor version digit — violates the grammar. **MUST** reject. | +| 17 | `COMP-VERSION-LEADING-ZEROS` | Compliance | [RFC 9112 §2.3](https://www.rfc-editor.org/rfc/rfc9112#section-2.3) | Grammar: `HTTP-version = HTTP-name "/" DIGIT "." DIGIT`. Each version component is exactly one DIGIT — "01" is two digits. **MUST** reject. | +| 18 | `COMP-VERSION-WHITESPACE` | Compliance | [RFC 9112 §2.3](https://www.rfc-editor.org/rfc/rfc9112#section-2.3) | Grammar: `HTTP-version = HTTP-name "/" DIGIT "." DIGIT`. No whitespace is permitted within the version token. **MUST** reject. | +| 19 | `RFC9112-6.1-CL-NON-NUMERIC` | Compliance | [RFC 9112 §6.3](https://www.rfc-editor.org/rfc/rfc9112#section-6.3) | "If a message is received without Transfer-Encoding and with an invalid Content-Length header field, then the message framing is invalid and the recipient **MUST** treat it as an unrecoverable error... the server **MUST** respond with a 400 (Bad Request) status code and then close the connection." | +| 20 | `RFC9112-6.1-CL-PLUS-SIGN` | Compliance | [RFC 9112 §6.3](https://www.rfc-editor.org/rfc/rfc9112#section-6.3) | Same as above — `Content-Length = 1*DIGIT`. A plus sign is not a DIGIT. **MUST** reject as invalid Content-Length. | +| 21 | `SMUG-DUPLICATE-CL` | Smuggling | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | "If a message is received without Transfer-Encoding and with an invalid Content-Length header field, then the message framing is invalid and the recipient **MUST** treat it as an unrecoverable error." Duplicate CL with different values = invalid. | +| 22 | `SMUG-CL-COMMA-DIFFERENT` | Smuggling | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | Same as above — comma-separated Content-Length values that differ are invalid. **MUST** treat as unrecoverable error. | +| 23 | `SMUG-CL-NEGATIVE` | Smuggling | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | `Content-Length = 1*DIGIT`. A minus sign is not a DIGIT. Invalid Content-Length — **MUST** reject. | +| 24 | `SMUG-CL-NEGATIVE-ZERO` | Smuggling | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | `Content-Length = 1*DIGIT`. "-0" starts with a minus sign. Invalid Content-Length — **MUST** reject. | +| 25 | `SMUG-CL-UNDERSCORE` | Smuggling | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | `Content-Length = 1*DIGIT`. Underscore is not a DIGIT. Invalid Content-Length — **MUST** reject. | +| 26 | `SMUG-CL-OCTAL` | Smuggling | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | `Content-Length = 1*DIGIT`. "0o5" contains non-DIGIT characters. **MUST** reject. | +| 27 | `SMUG-CL-HEX-PREFIX` | Smuggling | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | `Content-Length = 1*DIGIT`. "0x5" contains 'x'. **MUST** reject. | +| 28 | `SMUG-CL-INTERNAL-SPACE` | Smuggling | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | `Content-Length = 1*DIGIT`. Space is not a DIGIT and not OWS within the value. **MUST** reject. | +| 29 | `SMUG-TE-SP-BEFORE-COLON` | Smuggling | [RFC 9112 §5.1](https://www.rfc-editor.org/rfc/rfc9112#section-5) | "A server **MUST** reject, with a response status code of 400 (Bad Request), any received request message that contains whitespace between a header field name and colon." (Same rule as SP-BEFORE-COLON, applied to Transfer-Encoding.) | +| 30 | `SMUG-TE-NOT-FINAL-CHUNKED` | Smuggling | [RFC 9112 §6.3](https://www.rfc-editor.org/rfc/rfc9112#section-6.3) | "If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the final encoding, the message body length cannot be determined reliably; the server **MUST** respond with the 400 (Bad Request) status code and then close the connection." | +| 31 | `SMUG-TE-HTTP10` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | "A server or client that receives an HTTP/1.0 message containing a Transfer-Encoding header field **MUST** treat the message as if the framing is faulty, even if a Content-Length is present, and close the connection after processing the message." | +| 32 | `SMUG-TE-EMPTY-VALUE` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | `Transfer-Encoding = #transfer-coding`, `transfer-coding = token = 1*tchar`. An empty value does not match 1*tchar. **MUST** reject. | +| 33 | `SMUG-TE-DUPLICATE-HEADERS` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | Two Transfer-Encoding headers with conflicting Content-Length creates ambiguous framing. The combined TE + CL violates "A sender **MUST NOT** send a Content-Length header field in any message that contains a Transfer-Encoding header field." **MUST** reject. | +| 34 | `SMUG-TE-IDENTITY` | Smuggling | [RFC 9112 §7](https://www.rfc-editor.org/rfc/rfc9112#section-7) | "The 'identity' transfer coding was used in HTTP/1.1 and has been removed from the registry." An unrecognized coding with CL present. **MUST** reject per §6.1. | +| 35 | `SMUG-TE-VTAB` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | `transfer-coding = token = 1*tchar`. Vertical tab (0x0B) is not a tchar. The TE value is syntactically invalid — **MUST** reject. | +| 36 | `SMUG-TE-FORMFEED` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | `transfer-coding = token = 1*tchar`. Form feed (0x0C) is not a tchar. The TE value is syntactically invalid — **MUST** reject. | +| 37 | `SMUG-TE-NULL` | Smuggling | [RFC 9110 §5.5](https://www.rfc-editor.org/rfc/rfc9110#section-5.5) | "Field values containing CR, LF, or NUL characters are invalid and dangerous... a recipient of CR, LF, or NUL within a field value **MUST** either reject the message or replace each of those characters with SP before further processing." | +| 38 | `SMUG-BARE-CR-HEADER-VALUE` | Smuggling | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | "A recipient of such a bare CR **MUST** consider that element to be invalid or replace each bare CR with SP before processing the element or forwarding the message." | +| 39 | `SMUG-MULTIPLE-HOST-COMMA` | Smuggling | [RFC 9110 §7.2](https://www.rfc-editor.org/rfc/rfc9110#section-7.2) | "A server **MUST** respond with a 400 (Bad Request)... to any request message that contains... a Host header field with an invalid field value." Comma-separated values in Host are invalid. | +| 40 | `SMUG-TE-OBS-FOLD` | Smuggling | [RFC 9112 §5.2](https://www.rfc-editor.org/rfc/rfc9112#section-5.2) | "A server that receives an obs-fold in a request message... **MUST** either reject the message by sending a 400 (Bad Request)... or replace each received obs-fold with one or more SP octets." | +| 41 | `SMUG-CHUNK-BARE-SEMICOLON` | Smuggling | [RFC 9112 §7.1.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1.1) | Grammar: `chunk-ext = *( BWS ";" BWS chunk-ext-name [ "=" chunk-ext-val ] )`, `chunk-ext-name = token = 1*tchar`. Bare semicolon with no name violates the grammar. **MUST** reject. | +| 42 | `SMUG-CHUNK-HEX-PREFIX` | Smuggling | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | Grammar: `chunk-size = 1*HEXDIG`. "0x" prefix is not valid HEXDIG. **MUST** reject. | +| 43 | `SMUG-CHUNK-UNDERSCORE` | Smuggling | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | Grammar: `chunk-size = 1*HEXDIG`. Underscore is not a HEXDIG. **MUST** reject. | +| 44 | `SMUG-CHUNK-LEADING-SP` | Smuggling | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | Grammar: `chunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF`. No leading whitespace is permitted before chunk-size. **MUST** reject. | +| 45 | `SMUG-CHUNK-MISSING-TRAILING-CRLF` | Smuggling | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | Grammar: `chunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF`. The trailing CRLF after chunk-data is mandatory. **MUST** reject. | +| 46 | `SMUG-CHUNK-SPILL` | Smuggling | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | Chunk declares size 5 but sends 7 bytes. Server **MUST** read exactly chunk-size octets. Extra bytes corrupt framing. **MUST** reject. | +| 47 | `SMUG-CHUNK-NEGATIVE` | Smuggling | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | Grammar: `chunk-size = 1*HEXDIG`. A minus sign is not a HEXDIG. **MUST** reject. | +| 48 | `SMUG-CHUNK-EXT-CTRL` | Smuggling | [RFC 9112 §7.1.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1.1) | NUL byte (0x00) in chunk extension. NUL is not valid in any HTTP protocol element. RFC 9110 §5.5: "a recipient of CR, LF, or NUL within a field value **MUST** either reject the message or replace each of those characters with SP." | +| 49 | `SMUG-CHUNK-EXT-CR` | Smuggling | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | "A recipient of such a bare CR **MUST** consider that element to be invalid or replace each bare CR with SP before processing the element or forwarding the message." Bare CR in chunk extension is invalid. | +| 50 | `SMUG-CHUNK-BARE-CR-TERM` | Smuggling | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | "A recipient of such a bare CR **MUST** consider that element to be invalid or replace each bare CR with SP." Bare CR as line terminator is invalid — **MUST** reject. | +| 51 | `SMUG-CLTE-PIPELINE` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | "Regardless, the server **MUST** close the connection after responding to such a request to avoid the potential attacks." CL+TE combined — **MUST** close connection. | +| 52 | `SMUG-TECL-PIPELINE` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | Same as above — TE+CL combined in reverse smuggling direction. **MUST** close connection. | +| 53 | `SMUG-TE-XCHUNKED` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | Unknown TE with CL present: "Regardless, the server **MUST** close the connection after responding to such a request." Combined with §6.1: "A server that receives a request message with a transfer coding it does not understand **SHOULD** respond with 501." | +| 54 | `COMP-CONNECTION-CLOSE` | Compliance | [RFC 9112 §9.6](https://www.rfc-editor.org/rfc/rfc9112#section-9.6) | "A server that receives a 'close' connection option **MUST** initiate closure of the connection after it sends the final response to the request that contained the 'close' connection option." | +| 55 | `COMP-OPTIONS-STAR` | Compliance | [RFC 9112 §3.2.4](https://www.rfc-editor.org/rfc/rfc9112#section-3.2.4) | The asterisk-form `*` is defined only for OPTIONS. A valid OPTIONS * request **MUST** be accepted. | +| 56 | `COMP-POST-CL-BODY` | Compliance | [RFC 9112 §6.2](https://www.rfc-editor.org/rfc/rfc9112#section-6.2) | "If a valid Content-Length header field is present without Transfer-Encoding, its decimal value defines the expected message body length in octets." Server **MUST** accept a well-formed POST with matching body. | +| 57 | `COMP-POST-CL-ZERO` | Compliance | [RFC 9112 §6.2](https://www.rfc-editor.org/rfc/rfc9112#section-6.2) | Content-Length: 0 is a valid 1*DIGIT value. Server **MUST** accept zero-length body. | +| 58 | `COMP-POST-NO-CL-NO-TE` | Compliance | [RFC 9112 §6.3](https://www.rfc-editor.org/rfc/rfc9112#section-6.3) | "If this is a request message and none of the above are true, then the message body length is zero (no message body is present)." Server **MUST** treat as zero-length. | +| 59 | `COMP-CHUNKED-BODY` | Compliance | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | "A recipient **MUST** be able to parse and decode the chunked transfer coding." | +| 60 | `COMP-CHUNKED-MULTI` | Compliance | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | Same — multi-chunk is the standard chunked format. **MUST** accept. | +| 61 | `COMP-CHUNKED-EMPTY` | Compliance | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | A zero-length chunked body (just `0\r\n\r\n`) is valid. **MUST** accept. | +| 62 | `COMP-CHUNKED-HEX-UPPERCASE` | Compliance | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | `chunk-size = 1*HEXDIG`. HEXDIG includes A-F. **MUST** accept uppercase hex. | +| 63 | `COMP-CHUNKED-TRAILER-VALID` | Compliance | [RFC 9112 §7.1.2](https://www.rfc-editor.org/rfc/rfc9112#section-7.1.2) | "A recipient **MUST** be able to parse and decode the chunked transfer coding." Trailers are part of the chunked format. **MUST** accept. | +| 64 | `COMP-CHUNKED-EXTENSION` | Compliance | [RFC 9112 §7.1.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1.1) | "A recipient **MUST** ignore unrecognized chunk extensions." Server **MUST** accept and ignore. | +| 65 | `COMP-POST-CL-UNDERSEND` | Compliance | [RFC 9112 §6.2](https://www.rfc-editor.org/rfc/rfc9112#section-6.2) | "If the sender closes the connection or the recipient times out before the indicated number of octets are received, the recipient **MUST** consider the message to be incomplete and close the connection." | +| 66 | `COMP-CHUNKED-NO-FINAL` | Compliance | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | "The message body length is determined by reading and decoding the chunked data until the transfer coding indicates the data is complete." Without a zero terminator, the transfer is incomplete. Server **MUST** not process as complete. | +| 67 | `COMP-UPGRADE-POST` | Compliance | [RFC 6455 §4.1](https://www.rfc-editor.org/rfc/rfc6455#section-4.1) | "The method of the request **MUST** be GET, and the HTTP version **MUST** be at least 1.1." WebSocket upgrade via POST **MUST** not succeed. | +| 68 | `COMP-UPGRADE-MISSING-CONN` | Compliance | [RFC 9110 §7.8](https://www.rfc-editor.org/rfc/rfc9110#section-7.8) | "A sender of Upgrade **MUST** also send an 'Upgrade' connection option in the Connection header field." Without Connection: Upgrade, the server **MUST NOT** switch protocols. | +| 69 | `COMP-UPGRADE-UNKNOWN` | Compliance | [RFC 9110 §7.8](https://www.rfc-editor.org/rfc/rfc9110#section-7.8) | "A server **MUST NOT** switch to a protocol that was not indicated by the client in the corresponding request's Upgrade header field." Unknown protocol — **MUST NOT** return 101. | +| 70 | `MAL-NUL-IN-URL` | Malformed | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | NUL byte is not valid in any protocol element. Grammar violation — **MUST** reject. | +| 71 | `MAL-CONTROL-CHARS-HEADER` | Malformed | [RFC 9110 §5.5](https://www.rfc-editor.org/rfc/rfc9110#section-5.5) | "Field values containing CR, LF, or NUL characters are invalid and dangerous... a recipient **MUST** either reject the message or replace each of those characters with SP." (CTL characters outside safe context.) | +| 72 | `MAL-NON-ASCII-HEADER-NAME` | Malformed | [RFC 9112 §5](https://www.rfc-editor.org/rfc/rfc9112#section-5) | `field-name = token = 1*tchar`. Non-ASCII bytes are not tchar. Grammar violation — **MUST** reject. | +| 73 | `MAL-NON-ASCII-URL` | Malformed | [RFC 9112 §3](https://www.rfc-editor.org/rfc/rfc9112#section-3) | Non-ASCII bytes in the request-target violate the URI grammar. "A recipient **SHOULD NOT** attempt to autocorrect... since the invalid request-line might be deliberately crafted to bypass security filters." | +| 74 | `MAL-CL-OVERFLOW` | Malformed | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | "A recipient **MUST** anticipate potentially large decimal numerals and prevent parsing errors due to integer conversion overflows or precision loss due to integer conversion." | +| 75 | `MAL-NUL-IN-HEADER-VALUE` | Malformed | [RFC 9110 §5.5](https://www.rfc-editor.org/rfc/rfc9110#section-5.5) | "Field values containing CR, LF, or NUL characters are invalid and dangerous... a recipient of CR, LF, or NUL within a field value **MUST** either reject the message or replace each of those characters with SP." | +| 76 | `MAL-CHUNK-SIZE-OVERFLOW` | Malformed | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | "Recipients **MUST** anticipate potentially large hexadecimal numerals and prevent parsing errors due to integer conversion overflows or precision loss due to integer conversion." | +| 77 | `MAL-CL-EMPTY` | Malformed | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | `Content-Length = 1*DIGIT`. Empty value does not match 1*DIGIT (requires at least one). **MUST** reject as invalid CL. | +| 78 | `MAL-URL-OVERLONG-UTF8` | Malformed | [RFC 3629 §3](https://www.rfc-editor.org/rfc/rfc3629#section-3) | "Implementations of the decoding algorithm above **MUST** protect against decoding invalid sequences." Overlong UTF-8 (0xC0 0xAF) is explicitly invalid per RFC 3629. | +| 79 | `NORM-SP-BEFORE-COLON-CL` | Normalization | [RFC 9112 §5.1](https://www.rfc-editor.org/rfc/rfc9112#section-5) | "A server **MUST** reject, with a response status code of 400 (Bad Request), any received request message that contains whitespace between a header field name and colon." | +| 80 | `NORM-TAB-IN-NAME` | Normalization | [RFC 9112 §5](https://www.rfc-editor.org/rfc/rfc9112#section-5) | `field-name = token = 1*tchar`. Tab (0x09) is not a tchar. **MUST** reject — invalid token character. | +| 81 | `COMP-UPGRADE-INVALID-VER` | Compliance | [RFC 6455 §4.4](https://www.rfc-editor.org/rfc/rfc6455#section-4.4) | "If the server doesn't support the requested version, it **MUST** abort the WebSocket handshake." (426 Upgrade Required preferred.) | +| 82 | `COMP-UNKNOWN-TE-501` | Compliance | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | "A server that receives a request message with a transfer coding it does not understand **SHOULD** respond with 501." Combined with unknown-TE-without-CL making body length indeterminate: **MUST** reject. | +| 83 | `SMUG-TE-TRAILING-SPACE` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | "chunked " (with trailing space) is not an exact match for the registered coding "chunked". Combined with CL present: "the server **MUST** close the connection after responding." | +| 84 | `MAL-POST-CL-HUGE-NO-BODY` | Malformed | [RFC 9112 §6.2](https://www.rfc-editor.org/rfc/rfc9112#section-6.2) | "If the sender closes the connection or the recipient times out before the indicated number of octets are received, the recipient **MUST** consider the message to be incomplete and close the connection." | + +--- + +## SHOULD-Level Requirements (24 tests) + +The RFC recommends this behavior. Valid exceptions exist but must be understood and justified. + +| # | Test ID | Suite | RFC | RFC Quote | +|---|---------|-------|-----|-----------| +| 1 | `COMP-HTTP10-DEFAULT-CLOSE` | Compliance | [RFC 9112 §9.3](https://www.rfc-editor.org/rfc/rfc9112#section-9.3) | "HTTP implementations **SHOULD** support persistent connections." HTTP/1.0 without keep-alive: server **SHOULD** close after response. | +| 2 | `COMP-LEADING-CRLF` | Compliance | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | "A server that is expecting to receive and parse a request-line **SHOULD** ignore at least one empty line (CRLF) received prior to the request-line." | +| 3 | `RFC9112-3-MULTI-SP-REQUEST-LINE` | Compliance | [RFC 9112 §3](https://www.rfc-editor.org/rfc/rfc9112#section-3) | "A recipient **SHOULD NOT** attempt to autocorrect and then process the request without a redirect, since the invalid request-line might be deliberately crafted to bypass security filters." Multiple spaces = invalid request-line grammar. | +| 4 | `RFC9112-3.2-FRAGMENT-IN-TARGET` | Compliance | [RFC 9112 §3.2](https://www.rfc-editor.org/rfc/rfc9112#section-3.2) | "Recipients of an invalid request-line **SHOULD** respond with either a 400 (Bad Request) error or a 301 (Moved Permanently) redirect." Fragment (#) is not part of origin-form. | +| 5 | `RFC9112-2.3-HTTP09-REQUEST` | Compliance | [RFC 9112 §2.3](https://www.rfc-editor.org/rfc/rfc9112#section-2.3) | HTTP/0.9 has no version token. "Recipients of an invalid request-line **SHOULD** respond with either a 400 (Bad Request) error." | +| 6 | `RFC9112-2.3-INVALID-VERSION` | Compliance | [RFC 9112 §2.3](https://www.rfc-editor.org/rfc/rfc9112#section-2.3) | Invalid HTTP-version format. "Recipients of an invalid request-line **SHOULD** respond with either a 400 (Bad Request) error." (No explicit MUST — the Requirement field says "No MUST".) | +| 7 | `COMP-REQUEST-LINE-TAB` | Compliance | [RFC 9112 §3](https://www.rfc-editor.org/rfc/rfc9112#section-3) | Grammar: `request-line = method SP request-target SP HTTP-version`. SP is specifically 0x20. Tab is not SP. "A recipient **SHOULD NOT** attempt to autocorrect." **SHOULD** reject, **MAY** accept. | +| 8 | `COMP-METHOD-TRACE` | Compliance | [RFC 9110 §9.3.8](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.8) | "A client **MUST NOT** send content in a TRACE request." Servers **SHOULD** disable TRACE in production to prevent cross-site tracing (XST). | +| 9 | `COMP-TRACE-WITH-BODY` | Compliance | [RFC 9110 §9.3.8](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.8) | "A client **MUST NOT** send content in a TRACE request." Server **SHOULD** reject TRACE with body — 400/405 preferred. | +| 10 | `COMP-METHOD-CONNECT` | Compliance | [RFC 9110 §9.3.6](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.6) | "An origin server **MAY** accept a CONNECT request, but most origin servers do not implement CONNECT." Origin server **SHOULD** reject with 400/405/501. | +| 11 | `SMUG-CL-LEADING-ZEROS` | Smuggling | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | `Content-Length = 1*DIGIT`. "0005" matches the grammar but creates parser-disagreement risk (octal vs decimal interpretation). **SHOULD** reject. | +| 12 | `SMUG-CL-TRAILING-SPACE` | Smuggling | [RFC 9110 §5.5](https://www.rfc-editor.org/rfc/rfc9110#section-5.5) | OWS trimming is valid per `field-value = *( field-content )`. But trailing space in CL value is unusual. **SHOULD** be trimmed per OWS rules. | +| 13 | `SMUG-CL-EXTRA-LEADING-SP` | Smuggling | [RFC 9110 §5.5](https://www.rfc-editor.org/rfc/rfc9110#section-5.5) | Extra leading whitespace (double space) as OWS. Valid per `OWS = *( SP / HTAB )` but unusual. **SHOULD** trim. | +| 14 | `SMUG-CL-DOUBLE-ZERO` | Smuggling | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | "00" matches 1*DIGIT grammar but leading zero creates parser ambiguity. **SHOULD** reject — same class as CL-LEADING-ZEROS. | +| 15 | `SMUG-CL-LEADING-ZEROS-OCTAL` | Smuggling | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | "0200" — octal 128 vs decimal 200. Parser disagreement vector. **SHOULD** reject to eliminate ambiguity. | +| 16 | `SMUG-TE-DOUBLE-CHUNKED` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | "A sender **MUST NOT** apply the chunked transfer coding more than once." Duplicate chunked with CL — ambiguous. **SHOULD** reject. | +| 17 | `SMUG-TE-CASE-MISMATCH` | Smuggling | [RFC 9110 §7.8](https://www.rfc-editor.org/rfc/rfc9110#section-7.8) | "Recipients **SHOULD** use case-insensitive comparison when matching each protocol-name." "Chunked" (capital C) **SHOULD** be recognized. | +| 18 | `SMUG-TE-TRAILING-COMMA` | Smuggling | [RFC 9110 §5.6.1](https://www.rfc-editor.org/rfc/rfc9110#section-5.6.1) | "A sender **MUST NOT** generate empty list elements." But "A recipient **MUST** parse and ignore a reasonable number of empty list elements." **SHOULD** handle gracefully. | +| 19 | `SMUG-TE-LEADING-COMMA` | Smuggling | [RFC 9110 §5.6.1](https://www.rfc-editor.org/rfc/rfc9110#section-5.6.1) | Same — leading comma creates empty list element. "A recipient **MUST** parse and ignore a reasonable number of empty list elements." **SHOULD** handle. | +| 20 | `MAL-BINARY-GARBAGE` | Malformed | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | "The server **SHOULD** respond with a 400 (Bad Request) response and close the connection." | +| 21 | `MAL-LONG-URL` | Malformed | [RFC 9112 §3](https://www.rfc-editor.org/rfc/rfc9112#section-3) | "A server that receives a request-target longer than any URI it wishes to parse **MUST** respond with a 414 (URI Too Long) status code." (MUST for 414 specifically, but SHOULD for having a limit.) | +| 22 | `MAL-LONG-METHOD` | Malformed | [RFC 9112 §3](https://www.rfc-editor.org/rfc/rfc9112#section-3) | "A server that receives a method longer than any that it implements **SHOULD** respond with a 501 (Not Implemented) status code." | +| 23 | `MAL-LONG-HEADER-VALUE` | Malformed | [RFC 9110 §5.4](https://www.rfc-editor.org/rfc/rfc9110#section-5.4) | "A server that receives a request header field line, field value, or set of fields larger than it wishes to process **MUST** respond with an appropriate 4xx (Client Error) status code." (MUST for 4xx, SHOULD for having a limit.) | +| 24 | `MAL-LONG-HEADER-NAME` | Malformed | [RFC 9110 §5.4](https://www.rfc-editor.org/rfc/rfc9110#section-5.4) | Same as above. | + +--- + +## MAY-Level Requirements (10 tests) + +The RFC explicitly permits either behavior. Both acceptance and rejection are fully compliant. + +| # | Test ID | Suite | RFC | RFC Quote | +|---|---------|-------|-----|-----------| +| 1 | `RFC9112-2.2-BARE-LF-REQUEST-LINE` | Compliance | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | "A recipient **MAY** recognize a single LF as a line terminator and ignore any preceding CR." | +| 2 | `RFC9112-2.2-BARE-LF-HEADER` | Compliance | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | Same — bare LF in headers. **MAY** accept. | +| 3 | `COMP-EXPECT-UNKNOWN` | Compliance | [RFC 9110 §10.1.1](https://www.rfc-editor.org/rfc/rfc9110#section-10.1.1) | "A server that receives an Expect field value containing a member other than 100-continue **MAY** respond with a 417 (Expectation Failed) status code." | +| 4 | `COMP-GET-WITH-CL-BODY` | Compliance | [RFC 9110 §9.3.1](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.1) | "Content received in a GET request has no generally defined semantics, cannot alter the meaning or target of the request, and might lead some implementations to reject the request." **MAY** reject. | +| 5 | `SMUG-CHUNK-EXT-LF` | Smuggling | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | "A recipient **MAY** recognize a single LF as a line terminator." Bare LF in chunk extension — **MAY** accept. | +| 6 | `SMUG-CHUNK-LF-TERM` | Smuggling | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | Same — bare LF as chunk data terminator. **MAY** accept. | +| 7 | `SMUG-CHUNK-LF-TRAILER` | Smuggling | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | Same — bare LF in chunked trailer termination. **MAY** accept. | +| 8 | `COMP-HTTP10-NO-HOST` | Compliance | [RFC 9112 §3.2](https://www.rfc-editor.org/rfc/rfc9112#section-3.2) | "A client **MUST** send a Host header field in all HTTP/1.1 request messages." This requirement applies only to HTTP/1.1. HTTP/1.0 without Host is valid. **MAY** accept or reject. | +| 9 | `COMP-HTTP12-VERSION` | Compliance | [RFC 9112 §2.3](https://www.rfc-editor.org/rfc/rfc9112#section-2.3) | HTTP/1.2 has a higher minor version. A server **MAY** accept or return 505. | +| 10 | `MAL-CL-TAB-BEFORE-VALUE` | Malformed | [RFC 9110 §5.6.3](https://www.rfc-editor.org/rfc/rfc9110#section-5.6.3) | `OWS = *( SP / HTAB )`. Tab is valid optional whitespace after the colon. Fully compliant — **MAY** accept. | + +--- + +## "ought to" Level (1 test) + +Weaker than SHOULD — recommends but does not normatively require. + +| # | Test ID | Suite | RFC | RFC Quote | +|---|---------|-------|-----|-----------| +| 1 | `SMUG-CL-TE-BOTH` | Smuggling | [RFC 9112 §6.3](https://www.rfc-editor.org/rfc/rfc9112#section-6.3) | "Such a message might indicate an attempt to perform request smuggling... and **ought to** be handled as an error." §6.1: "A server **MAY** reject a request that contains both Content-Length and Transfer-Encoding or process such a request in accordance with the Transfer-Encoding alone." | + +--- + +## Unscored Tests (18 tests) + +These tests are informational — they produce warnings but never fail. + +| # | Test ID | Suite | RFC | Notes | +|---|---------|-------|-----|-------| +| 1 | `SMUG-TRANSFER_ENCODING` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | `Transfer_Encoding` (underscore) is a valid token but not the standard header. Some parsers normalize. | +| 2 | `SMUG-CL-COMMA-SAME` | Smuggling | [RFC 9110 §8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) | "A recipient of a Content-Length header field value consisting of the same decimal value repeated as a comma-separated list **MAY** either reject the message as invalid or replace that invalid field value with a single instance." | +| 3 | `SMUG-CHUNKED-WITH-PARAMS` | Smuggling | [RFC 9112 §7](https://www.rfc-editor.org/rfc/rfc9112#section-7) | "The chunked coding does not define any parameters. Their presence **SHOULD** be treated as an error." | +| 4 | `SMUG-EXPECT-100-CL` | Smuggling | [RFC 9110 §10.1.1](https://www.rfc-editor.org/rfc/rfc9110#section-10.1.1) | Expect: 100-continue with CL — standard behavior, tested for proxy interaction. | +| 5 | `SMUG-TRAILER-CL` | Smuggling | [RFC 9110 §6.5.1](https://www.rfc-editor.org/rfc/rfc9110#section-6.5.1) | Content-Length in trailers — prohibited trailer field. **MUST NOT** be used for framing. | +| 6 | `SMUG-TRAILER-TE` | Smuggling | [RFC 9110 §6.5.1](https://www.rfc-editor.org/rfc/rfc9110#section-6.5.1) | Transfer-Encoding in trailers — prohibited trailer field. | +| 7 | `SMUG-TRAILER-HOST` | Smuggling | [RFC 9110 §6.5.2](https://www.rfc-editor.org/rfc/rfc9110#section-6.5.2) | Host in trailers — must not be used for routing. | +| 8 | `SMUG-TRAILER-AUTH` | Smuggling | [RFC 9110 §6.5.1](https://www.rfc-editor.org/rfc/rfc9110#section-6.5.1) | Authorization in trailers — prohibited trailer field. | +| 9 | `SMUG-TRAILER-CONTENT-TYPE` | Smuggling | [RFC 9110 §6.5.1](https://www.rfc-editor.org/rfc/rfc9110#section-6.5.1) | Content-Type in trailers — prohibited trailer field. | +| 10 | `SMUG-HEAD-CL-BODY` | Smuggling | [RFC 9110 §9.3.2](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.2) | HEAD with body — server must not leave body on connection. | +| 11 | `SMUG-OPTIONS-CL-BODY` | Smuggling | [RFC 9110 §9.3.7](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.7) | OPTIONS with body — server should consume or reject body. | +| 12 | `SMUG-TE-TAB-BEFORE-VALUE` | Smuggling | [RFC 9110 §5.5](https://www.rfc-editor.org/rfc/rfc9110#section-5.5) | Tab as OWS before TE value — valid per `OWS = *( SP / HTAB )`. | +| 13 | `SMUG-ABSOLUTE-URI-HOST-MISMATCH` | Smuggling | [RFC 9112 §3.2.2](https://www.rfc-editor.org/rfc/rfc9112#section-3.2.2) | Absolute-form URI host differs from Host header — routing confusion vector. | +| 14 | `COMP-ABSOLUTE-FORM` | Compliance | [RFC 9112 §3.2.2](https://www.rfc-editor.org/rfc/rfc9112#section-3.2.2) | Absolute-form request-target — server **MUST** accept per RFC but many reject. | +| 15 | `COMP-METHOD-CASE` | Compliance | [RFC 9110 §9.1](https://www.rfc-editor.org/rfc/rfc9110#section-9.1) | Methods are case-sensitive. Lowercase "get" is an unknown method. Server **SHOULD** respond 501. | +| 16 | `MAL-RANGE-OVERLAPPING` | Malformed | [RFC 9110 §14.2](https://www.rfc-editor.org/rfc/rfc9110#section-14.2) | "A server that supports range requests **MAY** ignore or reject a Range header field that contains... a ranges-specifier with more than two overlapping ranges." | +| 17 | `MAL-URL-BACKSLASH` | Malformed | N/A | Backslash is not a valid URI character. Some servers normalize to `/`. | +| 18 | `NORM-CASE-TE` | Normalization | N/A | All-uppercase TRANSFER-ENCODING — tests header name case normalization. | + +--- + +## N/A — Best-Practice / Defensive Tests (11 tests) + +These tests don't map to a single RFC 2119 keyword but enforce defensive best practices. + +| # | Test ID | Suite | RFC | RFC Quote / Rationale | +|---|---------|-------|-----|----------------------| +| 1 | `COMP-BASELINE` | Compliance | N/A | Sanity check — valid GET must return 2xx. | +| 2 | `MAL-MANY-HEADERS` | Malformed | [RFC 6585 §5](https://www.rfc-editor.org/rfc/rfc6585#section-5) | "The 431 status code indicates that the server is unwilling to process the request because its header fields are too large." Server should enforce header count limits. | +| 3 | `MAL-INCOMPLETE-REQUEST` | Malformed | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | Grammar not matched — server **SHOULD** respond 400 and close. Timeout also acceptable. | +| 4 | `MAL-EMPTY-REQUEST` | Malformed | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | Zero bytes — no grammar match possible. 400, close, or timeout acceptable. | +| 5 | `MAL-WHITESPACE-ONLY-LINE` | Malformed | [RFC 9112 §2.2](https://www.rfc-editor.org/rfc/rfc9112#section-2.2) | Whitespace-only request line — not an empty line (CRLF) and not a valid request-line. | +| 6 | `MAL-H2-PREFACE` | Malformed | [RFC 9113 §3.4](https://www.rfc-editor.org/rfc/rfc9113#section-3.4) | HTTP/2 preface on HTTP/1.1 port — protocol confusion. 400/505/close/timeout acceptable. | +| 7 | `MAL-URL-PERCENT-NULL` | Malformed | [RFC 9110 §5.5](https://www.rfc-editor.org/rfc/rfc9110#section-5.5) | Percent-encoded NUL (%00) — null byte injection risk. 400 = pass, 2xx/404 = warn. | +| 8 | `MAL-URL-PERCENT-CRLF` | Malformed | [RFC 9110 §5.5](https://www.rfc-editor.org/rfc/rfc9110#section-5.5) | Percent-encoded CRLF (%0d%0a) — header injection if decoded during parsing. 400 = pass, 2xx/404 = warn. | +| 9 | `MAL-CHUNK-EXT-64K` | Malformed | [RFC 9112 §7.1.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1.1) | "A server **ought to** limit the total length of chunk extensions." (CVE-2023-39326 class.) | +| 10 | `NORM-UNDERSCORE-CL` | Normalization | N/A | `Content_Length` — valid token but dangerous if normalized to `Content-Length`. Drop or reject = pass. | +| 11 | `NORM-UNDERSCORE-TE` | Normalization | N/A | `Transfer_Encoding` — same class of normalization attack. Drop or reject = pass. | + +--- + +## Requirement Level by Suite + +### Compliance Suite (57 tests) + +| Level | Tests | +|-------|-------| +| MUST | 38 | +| SHOULD | 10 | +| MAY | 6 | +| Unscored | 2 | +| N/A | 1 | + +### Smuggling Suite (60 tests) + +| Level | Tests | +|-------|-------| +| MUST | 34 | +| SHOULD | 9 | +| MAY | 3 | +| "ought to" | 1 | +| Unscored | 13 | + +### Malformed Input Suite (26 tests) + +| Level | Tests | +|-------|-------| +| MUST | 10 | +| SHOULD | 5 | +| MAY | 1 | +| Unscored | 2 | +| N/A | 8 | + +### Normalization Suite (5 tests) + +| Level | Tests | +|-------|-------| +| MUST | 2 | +| Unscored | 1 | +| N/A | 2 | + +--- + +## RFC Section Cross-Reference + +| RFC Section | Tests | Topic | +|-------------|-------|-------| +| RFC 9112 §2.2 | 14 | Line endings, bare CR/LF, message parsing | +| RFC 9112 §2.3 | 5 | HTTP version | +| RFC 9112 §3 | 8 | Request line, method, request-target | +| RFC 9112 §3.2 | 10 | Host header, request-target forms | +| RFC 9112 §5 | 7 | Header field syntax, sp-before-colon | +| RFC 9112 §5.2 | 2 | Obsolete line folding | +| RFC 9112 §6.1 | 16 | Transfer-Encoding, CL+TE ambiguity | +| RFC 9112 §6.2 | 4 | Content-Length body framing | +| RFC 9112 §6.3 | 5 | Message body length determination | +| RFC 9112 §7.1 | 15 | Chunked transfer coding format | +| RFC 9112 §7.1.1 | 4 | Chunk extensions | +| RFC 9112 §7.1.2 | 1 | Chunked trailer section | +| RFC 9112 §9.3-9.6 | 2 | Connection management | +| RFC 9110 §5.4-5.6 | 7 | Field limits, values, lists, tokens | +| RFC 9110 §7.2 | 1 | Host header semantics | +| RFC 9110 §7.8 | 4 | Upgrade | +| RFC 9110 §8.6 | 12 | Content-Length semantics | +| RFC 9110 §9.1-9.3 | 6 | Methods (GET, HEAD, CONNECT, OPTIONS, TRACE) | +| RFC 9110 §10.1.1 | 2 | Expect header | +| RFC 9110 §6.5 | 5 | Trailer field restrictions | +| RFC 9110 §14.2 | 1 | Range requests | +| RFC 6455 | 2 | WebSocket handshake | +| RFC 6585 | 3 | 431 status code | +| RFC 3629 | 1 | UTF-8 encoding | +| RFC 9113 | 1 | HTTP/2 preface | +| N/A | 7 | Best practice / defensive | diff --git a/docs/hugo.yaml b/docs/hugo.yaml index 9f4252c..44c5503 100644 --- a/docs/hugo.yaml +++ b/docs/hugo.yaml @@ -44,9 +44,20 @@ menu: - name: Glossary pageRef: /docs weight: 4 + - name: Contribute + weight: 5 - name: Add a Framework + parent: Contribute pageRef: /add-a-framework - weight: 5 + weight: 1 + - name: Add a Test + parent: Contribute + pageRef: /add-a-test + weight: 2 + - name: Add with AI Agent + parent: Contribute + pageRef: /add-with-ai-agent + weight: 3 - name: Search weight: 6 params: