Skip to content

fix: harden HTTP framing correctness - #24

Merged
zuudevs merged 10 commits into
mainfrom
hardening/http-correctness
Sep 15, 2026
Merged

zuudevs merged 10 commits into
mainfrom
hardening/http-correctness

Conversation

@zuudevs

@zuudevs zuudevs commented Sep 15, 2026

Copy link
Copy Markdown
Owner

Summary

Continues roadmap milestone v0.8 with the HTTP correctness review. This PR focuses on message-boundary safety, status-specific body semantics, chunk syntax, request framing policy, and the timeout/EOF contracts that affect connection reuse.

Response framing

  • centralizes response framing analysis before body-state selection
  • rejects Transfer-Encoding + Content-Length conflicts before reuse decisions
  • rejects framing fields on interim 1xx, 101, and 204 responses where v1 treats them as forbidden protocol input
  • keeps HEAD and 304 header-terminated while preserving allowed representation metadata
  • preserves strict duplicate Content-Length rejection

205 Reset Content

Fixes a reuse bug where 205 previously completed immediately after headers even without explicit framing.

New policy:

  • Content-Length: 0 completes and may remain reusable
  • non-zero Content-Length is rejected
  • zero-content chunked framing completes and may remain reusable
  • actual chunked content is rejected
  • no Content-Length/Transfer-Encoding is close-delimited, completes only at EOF, and is not reusable
  • close-delimited bytes on 205 are rejected as content

Chunked decoding

  • validates chunk extension names as tokens
  • validates token and quoted-string extension values
  • supports OWS/BWS around extension syntax
  • rejects empty extension names, missing values, malformed quoted strings, and control bytes
  • retains framing-critical trailer rejection

Request serialization

  • emits Content-Length: 0 for empty POST/PUT/PATCH requests
  • keeps empty GET/HEAD/DELETE free of an automatic zero Content-Length
  • retains exact caller Content-Length/body-size matching and request Transfer-Encoding rejection

Timeout / EOF contract

Documents the current v1 behavior:

  • connect timeout is one budget across endpoint attempts
  • write timeout is one shared budget across head + body transmission
  • read timeout bounds each wait for response progress
  • read timeout is not treated as EOF
  • explicit-length/chunked premature EOF becomes UnexpectedEof
  • valid close-delimited EOF is normal completion

Tests

Adds deterministic coverage for:

  • HEAD framing conflicts
  • 304 representation Content-Length
  • forbidden framing on interim/204/101
  • 205 CL0, non-zero CL, zero chunked, chunked content, close-delimited EOF/content
  • strict chunk extension grammar
  • empty content-method Content-Length policy

Roadmap

  • marks Result hardening and URL/query hardening complete
  • records this PR as the current HTTP correctness substep
  • leaves resource-bound review as the final v0.8 substep

Scope

No socket/platform implementation, connection-pool behavior, redirect status policy, TLS, compression, or streaming support is added here.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dad3407455

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +398 to +399
close_delimited_ = true;
stage_ = Stage::CloseDelimitedBody;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat unframed 205 responses as header-terminated

When an HTTP/1.1 server returns 205 Reset Content without framing headers and keeps the connection open, this branch enters CloseDelimitedBody and waits for EOF, so a valid response eventually fails with the configured read timeout. RFC 9110 §15.3.6 defines a 205 response as terminating at the end of its header section; complete it there and leave the connection eligible for reuse rather than requiring the peer to close it.

Useful? React with 👍 / 👎.

@zuudevs
zuudevs merged commit ed7eed4 into main Sep 15, 2026
6 checks passed
@zuudevs
zuudevs deleted the hardening/http-correctness branch September 15, 2026 01:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant