fix(date): slide the rfc850-date two-digit year window - #5670
fix(date): slide the rfc850-date two-digit year window#5670luantaraschi wants to merge 1 commit into
Conversation
parseHttpDate serves the HTTP cache: cache-handler reads Date, Expires and Last-Modified through it, and the cache interceptor validates Last-Modified with it. Nothing else calls it. Its rfc850-date branch mapped a two-digit year with the fixed 1970-2069 range RFC 6265 defines for cookies. RFC 9110 section 5.6.7 requires a sliding window instead: Recipients of a timestamp value in rfc850-date format, which uses a two-digit year, MUST interpret a timestamp that appears to be more than 50 years in the future as representing the most recent year in the past that had the same last two digits. The visible effect is a rejection, not a misreading, because makeDate validates the weekday against the year it settled on. Read in 2026, "Expires: Monday, 15-Jun-76 12:30:45 GMT" is 2076, whose 15 June is a Monday; the old mapping tried 1976, whose 15 June was a Tuesday, so the whole date came back undefined and the cache ignored the header. Take the century of the current year, then step one century down when the result lands more than 50 years ahead, or one up when it lands more than 49 years back. The window is exactly 100 years wide, so one century always fits.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #5670 +/- ##
==========================================
+ Coverage 93.43% 93.44% +0.01%
==========================================
Files 110 110
Lines 38733 38787 +54
==========================================
+ Hits 36190 36245 +55
+ Misses 2543 2542 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
In case the red X is what is holding this one, it comes from That test is the flake tracked in #5674, whose root cause turned out to be upstream: the Maglev SIGSEGV in nodejs/node#64841 on Node v24.15.0 and later. The signature here is the same one described there, with no TAP output, no subtests, and the file ending in 3.6s against a 15s watchdog. The diff is The branch is 6 commits behind |
parseHttpDatemaps a two-digit rfc850-date year with the fixed 1970-2069 range, citing RFC 6265:RFC 6265 is the cookie spec. This parser has no cookie callers:
cache-handler.jsreadsDate,ExpiresandLast-Modifiedthrough it, andinterceptor/cache.jsvalidatesLast-Modifiedwith it. For those, RFC 9110 section 5.6.7 applies, and it asks for a sliding window:What changes
The visible effect is a rejection rather than a misreading, because
makeDatevalidates the weekday against the year it settled on. A date written for 2076 carries 2076's weekday, which does not match 1976's, so the whole value is thrown away.Run against
mainand against this branch, in 2026:Sunday, 15-Jun-70 12:30:45 GMTundefinedWednesday, 15-Jun-72 12:30:45 GMTundefinedMonday, 15-Jun-76 12:30:45 GMTundefinedWednesday, 15-Jun-77 12:30:45 GMTWednesday, 15-Jun-94 12:30:45 GMTSaturday, 15-Jun-24 12:30:45 GMTWednesday, 15-Jun-50 12:30:45 GMTSo an
Expiresa server means for the 2070s is dropped and the response is not stored. Two-digit years 70 through 76 are affected today, and the range grows by one every year: in 2030 it will be 70 through 80. Everything from 1977 to 2069 is untouched.The change
Take the century of the current year, then step one century down when the result lands more than 50 years ahead, or one up when it lands more than 49 years back. The window is exactly 100 years wide, so exactly one century fits and no input is left without a reading.
Tests
Two things moved in
test/utils/date.js.The
fuzzing rfc850round trip pinnedminYear = 1970/maxYear = 2069. Those bounds were the old window written out, so they now derive from the current year:currentYear - 49tocurrentYear + 50. Still 1e6 iterations, still green.Added
RFC850 two-digit years slide with the clock, covering both edges of the window and the year just past it. The year-just-past case is built from the past date it must resolve to, sincemakeDatevalidates the weekday against the year it settled on.Every existing case in the
RFC850table still passes unchanged, including06-Nov-94staying in 1994 and18-Aug-50staying in 2050.node --test test/utils/date.js: 7 pass. With the change tolib/util/date.jsreverted, 2 of those fail and 5 still pass, so the new assertions are the ones doing the work.npx eslintis clean on both files.