From bc9d6be04ea86064fd60efe84e2aa5bbc3e78366 Mon Sep 17 00:00:00 2001 From: Diogo Martins Date: Sun, 15 Feb 2026 14:10:40 +0000 Subject: [PATCH] Add 2 new tests - COMP-RANGE-POST COMP-UPGRADE-HTTP10 --- docs/content/compliance/_index.md | 5 +- docs/content/docs/body/range-post.md | 46 ++++++++++++++++++ docs/content/docs/upgrade/upgrade-http10.md | 47 ++++++++++++++++++ docs/static/probe/render.js | 2 + .../TestCases/Suites/ComplianceSuite.cs | 48 +++++++++++++++++++ 5 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 docs/content/docs/body/range-post.md create mode 100644 docs/content/docs/upgrade/upgrade-http10.md diff --git a/docs/content/compliance/_index.md b/docs/content/compliance/_index.md index c4850e5..99e16f1 100644 --- a/docs/content/compliance/_index.md +++ b/docs/content/compliance/_index.md @@ -56,14 +56,15 @@ Each test sends a request that violates a specific **MUST** or **MUST NOT** requ 'COMP-POST-CL-UNDERSEND','COMP-CHUNKED-BODY','COMP-CHUNKED-MULTI', 'COMP-CHUNKED-EMPTY','COMP-CHUNKED-NO-FINAL', 'COMP-GET-WITH-CL-BODY','COMP-CHUNKED-EXTENSION', - 'COMP-CHUNKED-TRAILER-VALID','COMP-CHUNKED-HEX-UPPERCASE' + 'COMP-CHUNKED-TRAILER-VALID','COMP-CHUNKED-HEX-UPPERCASE', + 'COMP-RANGE-POST' ]}, { key: 'methods-upgrade', label: 'Methods & Upgrade', testIds: [ 'COMP-METHOD-CONNECT', 'COMP-UNKNOWN-TE-501','COMP-EXPECT-UNKNOWN','COMP-METHOD-TRACE', 'COMP-TRACE-WITH-BODY', 'COMP-UPGRADE-POST','COMP-UPGRADE-MISSING-CONN', - 'COMP-UPGRADE-UNKNOWN','COMP-UPGRADE-INVALID-VER', + 'COMP-UPGRADE-UNKNOWN','COMP-UPGRADE-INVALID-VER','COMP-UPGRADE-HTTP10', 'COMP-CONNECTION-CLOSE','COMP-HTTP10-DEFAULT-CLOSE','COMP-HTTP10-NO-HOST' ]} ]; diff --git a/docs/content/docs/body/range-post.md b/docs/content/docs/body/range-post.md new file mode 100644 index 0000000..9ca39f6 --- /dev/null +++ b/docs/content/docs/body/range-post.md @@ -0,0 +1,46 @@ +--- +title: "RANGE-POST" +description: "RANGE-POST test documentation" +weight: 13 +--- + +| | | +|---|---| +| **Test ID** | `COMP-RANGE-POST` | +| **Category** | Compliance | +| **Scored** | Yes | +| **RFC** | [RFC 9110 §14.2](https://www.rfc-editor.org/rfc/rfc9110#section-14.2) | +| **RFC Level** | MUST | +| **Expected** | `2xx` (Range ignored) | + +## What it sends + +A POST request with a `Range` header. The Range mechanism only applies to GET requests. + +```http +POST / HTTP/1.1\r\n +Host: localhost:8080\r\n +Content-Length: 5\r\n +Range: bytes=0-10\r\n +\r\n +hello +``` + +## What the RFC says + +> "A server MUST ignore a Range header field received with a request method that is unrecognized or for which range handling is not defined." — RFC 9110 §14.2 + +Range handling is only defined for GET (RFC 9110 §14.2). For all other methods, the server must ignore the Range header and process the request normally. + +## Why it matters + +If a server incorrectly applies Range semantics to a POST request (returning `206 Partial Content`), it could truncate the request body or cause unexpected behavior. The server should process the full POST body and return a normal `2xx` response. + +## Verdicts + +- **Pass** — Server returns `2xx` (correctly ignored Range for POST) +- **Fail** — Server returns `206` (incorrectly applied Range to POST) or any non-2xx response + +## Sources + +- [RFC 9110 §14.2](https://www.rfc-editor.org/rfc/rfc9110#section-14.2) diff --git a/docs/content/docs/upgrade/upgrade-http10.md b/docs/content/docs/upgrade/upgrade-http10.md new file mode 100644 index 0000000..da51d5e --- /dev/null +++ b/docs/content/docs/upgrade/upgrade-http10.md @@ -0,0 +1,47 @@ +--- +title: "UPGRADE-HTTP10" +description: "UPGRADE-HTTP10 test documentation" +weight: 5 +--- + +| | | +|---|---| +| **Test ID** | `COMP-UPGRADE-HTTP10` | +| **Category** | Compliance | +| **Scored** | Yes | +| **RFC** | [RFC 9110 §7.8](https://www.rfc-editor.org/rfc/rfc9110#section-7.8) | +| **RFC Level** | MUST | +| **Expected** | Not `101` | + +## What it sends + +An HTTP/1.0 request with WebSocket upgrade headers. The server must ignore the Upgrade field because it was received in an HTTP/1.0 request. + +```http +GET / HTTP/1.0\r\n +Host: localhost:8080\r\n +Connection: Upgrade\r\n +Upgrade: websocket\r\n +Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n +Sec-WebSocket-Version: 13\r\n +\r\n +``` + +## What the RFC says + +> "A server that receives an Upgrade header field in an HTTP/1.0 request MUST ignore that Upgrade field." — RFC 9110 §7.8 + +The Upgrade mechanism is an HTTP/1.1 feature. An HTTP/1.0 client cannot participate in protocol switching, so the server must not attempt it. + +## Why it matters + +If a server processes an Upgrade from an HTTP/1.0 client and returns `101 Switching Protocols`, the client likely cannot handle the protocol switch. This could lead to connection corruption or security issues, especially if a proxy is involved that speaks HTTP/1.0 to the backend. + +## Verdicts + +- **Pass** — Server returns any status other than `101` (correctly ignored Upgrade) +- **Fail** — Server returns `101 Switching Protocols` (incorrectly upgraded an HTTP/1.0 request) + +## Sources + +- [RFC 9110 §7.8](https://www.rfc-editor.org/rfc/rfc9110#section-7.8) diff --git a/docs/static/probe/render.js b/docs/static/probe/render.js index 6dff6b0..fcac80f 100644 --- a/docs/static/probe/render.js +++ b/docs/static/probe/render.js @@ -279,6 +279,8 @@ window.ProbeRender = (function () { 'COMP-POST-NO-CL-NO-TE': '/Http11Probe/docs/body/post-no-cl-no-te/', 'COMP-UNKNOWN-METHOD': '/Http11Probe/docs/request-line/unknown-method/', 'COMP-UNKNOWN-TE-501': '/Http11Probe/docs/request-line/unknown-te-501/', + 'COMP-RANGE-POST': '/Http11Probe/docs/body/range-post/', + 'COMP-UPGRADE-HTTP10': '/Http11Probe/docs/upgrade/upgrade-http10/', 'COMP-UPGRADE-INVALID-VER': '/Http11Probe/docs/upgrade/upgrade-invalid-ver/', 'COMP-UPGRADE-MISSING-CONN': '/Http11Probe/docs/upgrade/upgrade-missing-conn/', 'COMP-UPGRADE-POST': '/Http11Probe/docs/upgrade/upgrade-post/', diff --git a/src/Http11Probe/TestCases/Suites/ComplianceSuite.cs b/src/Http11Probe/TestCases/Suites/ComplianceSuite.cs index 1fc146b..7a0b535 100644 --- a/src/Http11Probe/TestCases/Suites/ComplianceSuite.cs +++ b/src/Http11Probe/TestCases/Suites/ComplianceSuite.cs @@ -1090,6 +1090,54 @@ public static IEnumerable GetTestCases() } }; + // ── Range / Conditional ───────────────────────────────────── + + yield return new TestCase + { + Id = "COMP-RANGE-POST", + Description = "Range header on POST must be ignored — Range only applies to GET", + Category = TestCategory.Compliance, + RfcReference = "RFC 9110 §14.2", + PayloadFactory = ctx => MakeRequest( + $"POST / HTTP/1.1\r\nHost: {ctx.HostHeader}\r\nContent-Length: 5\r\nRange: bytes=0-10\r\n\r\nhello"), + Expected = new ExpectedBehavior + { + Description = "2xx (Range ignored)", + CustomValidator = (response, state) => + { + if (response is null) + return state == ConnectionState.ClosedByServer ? TestVerdict.Fail : TestVerdict.Fail; + if (response.StatusCode == 206) + return TestVerdict.Fail; + if (response.StatusCode is >= 200 and < 300) + return TestVerdict.Pass; + return TestVerdict.Fail; + } + } + }; + + yield return new TestCase + { + Id = "COMP-UPGRADE-HTTP10", + Description = "Upgrade header in HTTP/1.0 request must be ignored", + Category = TestCategory.Compliance, + RfcReference = "RFC 9110 §7.8", + PayloadFactory = ctx => MakeRequest( + $"GET / HTTP/1.0\r\nHost: {ctx.HostHeader}\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n\r\n"), + Expected = new ExpectedBehavior + { + Description = "!101", + CustomValidator = (response, state) => + { + if (response is null) + return state == ConnectionState.ClosedByServer ? TestVerdict.Pass : TestVerdict.Fail; + if (response.StatusCode == 101) + return TestVerdict.Fail; + return TestVerdict.Pass; + } + } + }; + // ── RFC 9110 response semantics ────────────────────────────── yield return new TestCase