Skip to content

Commit dfc3420

Browse files
MDA2AVclaude
andcommitted
Add 22 glossary pages, split result tables into sub-tables
- Create docs/content/docs/upgrade/ with 4 test pages (UPGRADE-POST, UPGRADE-MISSING-CONN, UPGRADE-UNKNOWN, UPGRADE-INVALID-VER) - Add 3 request-line pages (METHOD-CONNECT, METHOD-CONNECT-NO-PORT, METHOD-TRACE) - Add 1 headers page (EXPECT-UNKNOWN) - Add 12 smuggling pages (chunk-ext-lf, chunk-spill, chunk-lf-term, chunk-ext-ctrl, chunk-lf-trailer, te-identity, chunk-negative, trailer-cl, trailer-te, trailer-host, head-cl-body, options-cl-body) - Add 2 malformed-input pages (CL-EMPTY, CL-TAB-BEFORE-VALUE) - Fix 4 stale RFC-prefix keys in render.js TEST_URLS (now SMUG- prefix) - Add 22 new TEST_URLS entries for all new tests - Add renderSubTables() to render.js with testIdFilter on renderTable() - Split Compliance into 8 sub-tables, Smuggling into 7, Malformed into 4 - Update all glossary _index.md files with cards for new tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2956261 commit dfc3420

35 files changed

Lines changed: 1333 additions & 35 deletions

docs/content/compliance/_index.md

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,6 @@ These tests validate that HTTP/1.1 servers correctly implement the protocol requ
1010

1111
Each test sends a request that violates a specific **MUST** or **MUST NOT** requirement from the RFCs. A compliant server should reject these with a `400 Bad Request` (or close the connection). Accepting the request silently means the server is non-compliant and potentially vulnerable to downstream attacks.
1212

13-
**What's tested:**
14-
- **Line endings** &mdash; bare `LF` without `CR`, `CR` without `LF` (RFC 9112 &sect;2.2)
15-
- **Request-line format** &mdash; multiple spaces, missing target, fragments in URI (RFC 9112 &sect;3)
16-
- **HTTP version** &mdash; invalid version strings, HTTP/0.9 requests (RFC 9112 &sect;2.3)
17-
- **Header syntax** &mdash; obs-fold, space before colon, empty names, invalid characters, missing colon (RFC 9112 &sect;5, RFC 9110 &sect;5.6.2)
18-
- **Host header** &mdash; missing or duplicate Host with conflicting values (RFC 9112 &sect;7.1, RFC 9110 &sect;5.4)
19-
- **Content-Length** &mdash; non-numeric, plus sign, overflow (RFC 9112 &sect;6.1)
20-
2113
<div id="lang-filter"></div>
2214
<div id="table-compliance"><p><em>Loading...</em></p></div>
2315

@@ -29,9 +21,44 @@ Each test sends a request that violates a specific **MUST** or **MUST NOT** requ
2921
document.getElementById('table-compliance').innerHTML = '<p><em>No probe data available yet. Run the Probe workflow manually on <code>main</code> to generate results.</em></p>';
3022
return;
3123
}
24+
var GROUPS = [
25+
{ key: 'baseline', label: 'Baseline', testIds: [
26+
'COMP-BASELINE'
27+
]},
28+
{ key: 'line-endings', label: 'Line Endings', testIds: [
29+
'RFC9112-2.2-BARE-LF-REQUEST-LINE','RFC9112-2.2-BARE-LF-HEADER',
30+
'RFC9112-3-CR-ONLY-LINE-ENDING','COMP-LEADING-CRLF','COMP-WHITESPACE-BEFORE-HEADERS'
31+
]},
32+
{ key: 'request-line', label: 'Request Line', testIds: [
33+
'RFC9112-3-MULTI-SP-REQUEST-LINE','RFC9112-3-MISSING-TARGET',
34+
'RFC9112-3.2-FRAGMENT-IN-TARGET','RFC9112-2.3-INVALID-VERSION',
35+
'RFC9112-2.3-HTTP09-REQUEST','COMP-ASTERISK-WITH-GET','COMP-OPTIONS-STAR',
36+
'COMP-CONNECT-EMPTY-PORT','COMP-ABSOLUTE-FORM','COMP-METHOD-CASE'
37+
]},
38+
{ key: 'headers', label: 'Header Syntax', testIds: [
39+
'RFC9112-5.1-OBS-FOLD','RFC9110-5.6.2-SP-BEFORE-COLON',
40+
'RFC9112-5-EMPTY-HEADER-NAME','RFC9112-5-INVALID-HEADER-NAME',
41+
'RFC9112-5-HEADER-NO-COLON'
42+
]},
43+
{ key: 'host', label: 'Host Header', testIds: [
44+
'RFC9112-7.1-MISSING-HOST','RFC9110-5.4-DUPLICATE-HOST',
45+
'COMP-DUPLICATE-HOST-SAME','COMP-HOST-WITH-USERINFO','COMP-HOST-WITH-PATH'
46+
]},
47+
{ key: 'content-length', label: 'Content-Length', testIds: [
48+
'RFC9112-6.1-CL-NON-NUMERIC','RFC9112-6.1-CL-PLUS-SIGN'
49+
]},
50+
{ key: 'methods', label: 'Methods & Routing', testIds: [
51+
'COMP-METHOD-CONNECT','COMP-METHOD-CONNECT-NO-PORT',
52+
'COMP-UNKNOWN-TE-501','COMP-EXPECT-UNKNOWN','COMP-METHOD-TRACE'
53+
]},
54+
{ key: 'upgrade', label: 'Upgrade / WebSocket', testIds: [
55+
'COMP-UPGRADE-POST','COMP-UPGRADE-MISSING-CONN',
56+
'COMP-UPGRADE-UNKNOWN','COMP-UPGRADE-INVALID-VER'
57+
]}
58+
];
3259
function render(data) {
3360
var ctx = ProbeRender.buildLookups(data.servers);
34-
ProbeRender.renderTable('table-compliance', 'Compliance', ctx);
61+
ProbeRender.renderSubTables('table-compliance', 'Compliance', ctx, GROUPS);
3562
}
3663
render(window.PROBE_DATA);
3764
ProbeRender.renderLanguageFilter('lang-filter', window.PROBE_DATA, render);

docs/content/docs/_index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ Reference documentation for every test in Http11Probe, organized by topic. Each
1717
{{< card link="content-length" title="Content-Length" subtitle="Non-numeric CL, plus sign, integer overflow, leading zeros, negative values." icon="calculator" >}}
1818
{{< card link="smuggling" title="Request Smuggling" subtitle="CL+TE conflicts, TE obfuscation, pipeline injection, and why ambiguous framing is dangerous." icon="shield-exclamation" >}}
1919
{{< card link="malformed-input" title="Malformed Input" subtitle="Binary garbage, oversized fields, control characters, incomplete requests." icon="lightning-bolt" >}}
20+
{{< card link="upgrade" title="Upgrade / WebSocket" subtitle="Protocol upgrade validation, WebSocket handshake method and version checks." icon="arrow-up" >}}
2021
{{< /cards >}}

docs/content/docs/headers/_index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ HTTP header fields follow a strict grammar: `field-name ":" OWS field-value OWS`
2929
{{< card link="invalid-header-name" title="INVALID-HEADER-NAME" subtitle="Non-token characters in field name." >}}
3030
{{< card link="header-no-colon" title="HEADER-NO-COLON" subtitle="Header line with no colon separator." >}}
3131
{{< card link="whitespace-before-headers" title="WHITESPACE-BEFORE-HEADERS" subtitle="Whitespace before the first header line." >}}
32+
{{< card link="expect-unknown" title="EXPECT-UNKNOWN" subtitle="Unknown Expect value. Should respond with 417." >}}
3233
{{< /cards >}}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
title: "EXPECT-UNKNOWN"
3+
description: "EXPECT-UNKNOWN test documentation"
4+
weight: 7
5+
---
6+
7+
| | |
8+
|---|---|
9+
| **Test ID** | `COMP-EXPECT-UNKNOWN` |
10+
| **Category** | Compliance |
11+
| **RFC** | [RFC 9110 Section 10.1.1](https://www.rfc-editor.org/rfc/rfc9110#section-10.1.1) |
12+
| **Requirement** | MUST respond with 417 |
13+
| **Expected** | `417`; `2xx` is a warning |
14+
15+
## What it sends
16+
17+
`Expect: 200-ok` — an Expect header with a value the server cannot fulfill.
18+
19+
## What the RFC says
20+
21+
> "A server that receives an Expect field value containing a member other than 100-continue MAY respond with a 417 (Expectation Failed) status code to indicate that the unexpected expectation cannot be met." — RFC 9110 Section 10.1.1
22+
23+
While the RFC uses "MAY", a `417 Expectation Failed` is the semantically correct response for an unrecognized Expect value. Silently ignoring unknown expectations is permissible but less strict.
24+
25+
## Why it matters
26+
27+
The Expect mechanism is a contract between client and server. If a server ignores unknown Expect values, clients cannot rely on the mechanism for future extensions. Returning `417` signals clear rejection of unsupported expectations.
28+
29+
## Sources
30+
31+
- [RFC 9110 Section 10.1.1](https://www.rfc-editor.org/rfc/rfc9110#section-10.1.1)

docs/content/docs/malformed-input/_index.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,11 @@ These tests send pathological, oversized, or completely invalid payloads. The go
3636
{{< card link="chunk-size-overflow" title="CHUNK-SIZE-OVERFLOW" subtitle="Chunk size integer overflow." >}}
3737
{{< card link="h2-preface" title="H2-PREFACE" subtitle="HTTP/2 preface sent to HTTP/1.1 server." >}}
3838
{{< card link="chunk-extension-long" title="CHUNK-EXTENSION-LONG" subtitle="100KB chunk extension value." >}}
39+
{{< card link="cl-empty" title="CL-EMPTY" subtitle="Empty Content-Length value." >}}
40+
{{< /cards >}}
41+
42+
### Unscored
43+
44+
{{< cards >}}
45+
{{< card link="cl-tab-before-value" title="CL-TAB-BEFORE-VALUE" subtitle="Tab as OWS before Content-Length value." >}}
3946
{{< /cards >}}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
title: "CL-EMPTY"
3+
description: "CL-EMPTY test documentation"
4+
weight: 19
5+
---
6+
7+
| | |
8+
|---|---|
9+
| **Test ID** | `MAL-CL-EMPTY` |
10+
| **Category** | Malformed Input |
11+
| **RFC** | [RFC 9110 Section 8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6) |
12+
| **Requirement** | MUST reject |
13+
| **Expected** | `400` or close |
14+
15+
## What it sends
16+
17+
`Content-Length: ` — a Content-Length header with an empty value (just whitespace after the colon).
18+
19+
## What the RFC says
20+
21+
> "Content-Length = 1*DIGIT" — RFC 9110 Section 8.6
22+
23+
The grammar requires at least one digit. An empty value is not a valid Content-Length and indicates invalid message framing.
24+
25+
## Why it matters
26+
27+
Parsers that treat an empty Content-Length as `0` will read no body, while others may reject it or wait for data. This disagreement between parsers can be exploited for smuggling when the request also carries a body.
28+
29+
## Sources
30+
31+
- [RFC 9110 Section 8.6](https://www.rfc-editor.org/rfc/rfc9110#section-8.6)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
title: "CL-TAB-BEFORE-VALUE"
3+
description: "CL-TAB-BEFORE-VALUE test documentation"
4+
weight: 20
5+
---
6+
7+
| | |
8+
|---|---|
9+
| **Test ID** | `MAL-CL-TAB-BEFORE-VALUE` |
10+
| **Category** | Malformed Input |
11+
| **RFC** | [RFC 9110 Section 5.5](https://www.rfc-editor.org/rfc/rfc9110#section-5.5) |
12+
| **Requirement** | valid per RFC |
13+
| **Expected** | `400` preferred; `2xx` is a warning |
14+
15+
## What it sends
16+
17+
`Content-Length:\t5` — a Content-Length header where a horizontal tab character separates the colon from the value, instead of a space.
18+
19+
## What the RFC says
20+
21+
> "OWS = *( SP / HTAB )" — RFC 9110 Section 5.6.3
22+
23+
The optional whitespace (OWS) between the colon and the field value may be either spaces or horizontal tabs. A tab character is technically valid per the grammar.
24+
25+
## Why it matters
26+
27+
While tabs are valid OWS, they are rarely used in practice. Some parsers may not handle tab characters correctly — for example, treating the tab as part of the value rather than whitespace, resulting in a failed integer parse or a different numeric interpretation. This edge case tests parser robustness.
28+
29+
## Sources
30+
31+
- [RFC 9110 Section 5.5](https://www.rfc-editor.org/rfc/rfc9110#section-5.5)
32+
- [RFC 9110 Section 5.6.3](https://www.rfc-editor.org/rfc/rfc9110#section-5.6.3)

docs/content/docs/request-line/_index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ Note this is a SHOULD, not a MUST. The RFC recommends 400 but does not mandate i
2626
{{< card link="options-star" title="OPTIONS-STAR" subtitle="OPTIONS * — valid asterisk-form request." >}}
2727
{{< card link="unknown-te-501" title="UNKNOWN-TE-501" subtitle="Unknown Transfer-Encoding without CL." >}}
2828
{{< card link="connect-empty-port" title="CONNECT-EMPTY-PORT" subtitle="CONNECT with empty port in authority-form." >}}
29+
{{< card link="method-connect" title="METHOD-CONNECT" subtitle="CONNECT to an origin server must be rejected." >}}
30+
{{< card link="method-connect-no-port" title="METHOD-CONNECT-NO-PORT" subtitle="CONNECT without port in authority-form." >}}
2931
{{< /cards >}}
3032

3133
### Unscored
3234

3335
{{< cards >}}
3436
{{< card link="absolute-form" title="ABSOLUTE-FORM" subtitle="Absolute-form request-target (http://host/)." >}}
3537
{{< card link="method-case" title="METHOD-CASE" subtitle="Lowercase method 'get'. Methods are case-sensitive." >}}
38+
{{< card link="method-trace" title="METHOD-TRACE" subtitle="TRACE request — should be disabled in production." >}}
3639
{{< /cards >}}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
title: "METHOD-CONNECT-NO-PORT"
3+
description: "METHOD-CONNECT-NO-PORT test documentation"
4+
weight: 13
5+
---
6+
7+
| | |
8+
|---|---|
9+
| **Test ID** | `COMP-METHOD-CONNECT-NO-PORT` |
10+
| **Category** | Compliance |
11+
| **RFC** | [RFC 9112 Section 3.2.3](https://www.rfc-editor.org/rfc/rfc9112#section-3.2.3) |
12+
| **Requirement** | MUST reject |
13+
| **Expected** | `400` or close |
14+
15+
## What it sends
16+
17+
`CONNECT example.com HTTP/1.1` — a CONNECT request with authority-form that is missing the required port.
18+
19+
## What the RFC says
20+
21+
> "The 'authority-form' of request-target is only used for CONNECT requests... authority = uri-host ':' port" — RFC 9112 Section 3.2.3
22+
23+
The authority-form grammar requires both host and port separated by a colon. Omitting the port makes the request-target invalid.
24+
25+
## Why it matters
26+
27+
A server or proxy that accepts CONNECT without a port must guess the target port, which can lead to unexpected connections. This is a parsing ambiguity that could be exploited for SSRF or port confusion attacks.
28+
29+
## Sources
30+
31+
- [RFC 9112 Section 3.2.3](https://www.rfc-editor.org/rfc/rfc9112#section-3.2.3)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
title: "METHOD-CONNECT"
3+
description: "METHOD-CONNECT test documentation"
4+
weight: 12
5+
---
6+
7+
| | |
8+
|---|---|
9+
| **Test ID** | `COMP-METHOD-CONNECT` |
10+
| **Category** | Compliance |
11+
| **RFC** | [RFC 9110 Section 9.3.6](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.6) |
12+
| **Requirement** | origin server SHOULD reject |
13+
| **Expected** | `400`, `405`, `501`, or close |
14+
15+
## What it sends
16+
17+
`CONNECT example.com:443 HTTP/1.1` — a CONNECT request sent directly to an origin server (not a proxy).
18+
19+
## What the RFC says
20+
21+
> "CONNECT is intended only for use in requests to a proxy... A server that does not act as a tunnel for the requested host and port, or which chooses not to open a TCP connection, MUST respond with an appropriate error status code." — RFC 9110 Section 9.3.6
22+
23+
Origin servers are not proxies. They have no reason to accept CONNECT and establish a TCP tunnel.
24+
25+
## Why it matters
26+
27+
If an origin server accepts CONNECT, it effectively becomes an open proxy. This can be exploited for port scanning internal networks, bypassing firewalls, or pivoting attacks through the server.
28+
29+
## Sources
30+
31+
- [RFC 9110 Section 9.3.6](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.6)

0 commit comments

Comments
 (0)