Skip to content

Emit a Date header on all responses (RFC 9110 §6.6.1) - #231

Merged
swhitty merged 2 commits into
swhitty:mainfrom
ianegordon:ian/tvt-1057-emit-a-date-header-on-all-responses-rfc-9110-661-must
Jul 28, 2026
Merged

Emit a Date header on all responses (RFC 9110 §6.6.1)#231
swhitty merged 2 commits into
swhitty:mainfrom
ianegordon:ian/tvt-1057-emit-a-date-header-on-all-responses-rfc-9110-661-must

Conversation

@ianegordon

Copy link
Copy Markdown
Contributor

Summary

Two related conformance fixes for HTTP date handling:

  1. IMF-fixdate formatting — HTTP dates are now formatted per RFC 9110 §5.6.7 via a new shared HTTPDate formatter: pattern "EEE, dd MMM yyyy HH:mm:ss 'GMT'". The previous pattern ("EEE, d MMM yyyy HH:mm:ss zzz") emitted single-digit days, violating the ABNF (day = 2DIGIT), and relied on locale behaviour for the zone name instead of the literal GMT. HTTPCacheControl and the file/directory handlers now share this single formatter.

  2. Date header on every response — RFC 9110 §6.6.1: "An origin server with a clock … MUST generate a Date header field in all 2xx (Successful), 3xx (Redirection), and 4xx (Client Error) responses, and MAY generate a Date header field in 1xx (Informational) and 5xx (Server Error) responses." HTTPConnection.sendResponse now injects an IMF-fixdate Date when the response doesn't already carry one (unconditionally across status classes — conformant and simpler). Handler-supplied Date values are never overwritten. Since sendResponse is the single server egress, framework-authored responses (404 unhandled, 500 handler-throw, timeout) are covered without running user code.

Tests

All 456 package tests pass.

  • HTTPDateTests: exact output for both RFC example dates ("Sun, 06 Nov 1994 08:49:37 GMT", "Tue, 15 Nov 1994 08:12:31 GMT"), zero-padded-day case, format→parse round-trip.
  • HTTPConnectionTests: generated well-formed Date on a 200; byte-exact test proving a supplied Date is preserved verbatim.
  • HTTPServerTests: wire-level assertions that 404-unhandled, 500-handler-throw, and timeout responses carry a well-formed IMF-fixdate Date.

Notes

  • Per-response cost measured at ~1.4 µs per format call on Apple Silicon (~1.4% of one core at 10k req/s). If that ever matters, the usual mitigation is a once-per-second cached string; not done here to keep the change minimal.
  • DateFormatter thread safety is documented for Apple platforms (iOS 7+/macOS 10.9+); swift-corelibs-foundation documents no equivalent guarantee. The shared-static-formatter pattern already existed in HTTPCacheControl; this PR extends its use to every response.

🤖 Generated with Claude Code

@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.87%. Comparing base (ac24c58) to head (5b3298d).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #231      +/-   ##
==========================================
+ Coverage   92.83%   92.87%   +0.03%     
==========================================
  Files          71       72       +1     
  Lines        3743     3748       +5     
==========================================
+ Hits         3475     3481       +6     
+ Misses        268      267       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

ianegordon and others added 2 commits July 23, 2026 12:42
RFC 9110 §5.6.7 requires a two-digit day (day = 2DIGIT) and the
literal "GMT"; the previous pattern "EEE, d MMM yyyy HH:mm:ss zzz"
emitted single-digit days and relied on locale behaviour for the
zone name. HTTPDate is now the single source of truth for HTTP
date formatting (TVT-294).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RFC 9110 §6.6.1: an origin server with a clock MUST generate a Date
header field in all 2xx, 3xx and 4xx responses and MAY in 1xx/5xx.
HTTPConnection.sendResponse now injects an IMF-fixdate Date when the
response does not already carry one; handler-supplied values are
preserved. Covers framework-authored responses (404 unhandled, 500
handler-throw, timeout) that never run user code (TVT-1057).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ianegordon
ianegordon force-pushed the ian/tvt-1057-emit-a-date-header-on-all-responses-rfc-9110-661-must branch from 5d61306 to 5b3298d Compare July 23, 2026 16:42

@swhitty swhitty left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

looks great, thanks

@swhitty
swhitty merged commit 82fa8b4 into swhitty:main Jul 28, 2026
13 checks passed
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.

2 participants