Skip to content

fix(server): honor static freshness validators - #2715

Merged
james-elicx merged 9 commits into
cloudflare:mainfrom
Boyeep:fix/static-conditional-requests
Jul 27, 2026
Merged

fix(server): honor static freshness validators#2715
james-elicx merged 9 commits into
cloudflare:mainfrom
Boyeep:fix/static-conditional-requests

Conversation

@Boyeep

@Boyeep Boyeep commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • build on the merged fix(server): use weak comparison for If-None-Match #2710 entity-tag parser and extend static serving to the full RFC precondition order
  • support strong If-Match, If-Unmodified-Since, weak If-None-Match, and strict HTTP-date handling
  • evaluate preconditions before byte ranges and honor Cache-Control: no-cache
  • support single bytes ranges with correct 206 and 416 responses
  • ignore unusable effective modification dates instead of incorrectly failing If-Unmodified-Since
  • preserve conditional and range request headers when forwarding Worker asset requests
  • cover both startup-cache and filesystem-fallback production paths

Branch refresh

Rebuilt directly on current main at c9a4a843c, which contains the final merged #2710 implementation. The stale #2710 merge ancestry and the discarded dev public-file ETag index are gone. The range behavior previously stacked from #2711 is included in this single clean commit.

Next.js parity

Next.js static serving delegates freshness and range evaluation to its send/fresh stack. This change matches the observable validator precedence and freshness behavior while preserving vinext byte-range and multi-runtime behavior.

Validation

  • 437 targeted tests passed across conditional parsing, HTTP dates, ranges, static serving/cache, Worker forwarding, static image emission, and App Router production serving
  • all 15 changed files pass scoped format, lint, and type checks
  • vp run vinext#build passed
  • exact-head CI and re-review pending on the refreshed branch

@pkg-pr-new

pkg-pr-new Bot commented Jul 26, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@2715
npm i https://pkg.pr.new/create-vinext-app@2715
npm i https://pkg.pr.new/@vinext/types@2715
npm i https://pkg.pr.new/vinext@2715

commit: b997294

@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared b997294 against base c9a4a84 using alternating same-runner rounds. Next.js was unchanged and skipped.

0 improved · 0 regressed · 6 within ±1.5%

Scenario Framework Baseline Current Change
Client bundle size (gzip) vinext 132.4 KB 132.4 KB ⚫ -0.0%
Client entry size (gzip) vinext 119.8 KB 119.8 KB ⚫ -0.0%
Dev server cold start vinext 2.08 s 2.10 s ⚫ +0.9%
Production build time vinext 2.15 s 2.14 s ⚫ -0.3%
RSC entry closure size (gzip) vinext 105.6 KB 105.6 KB ⚫ 0.0%
Server bundle size (gzip) vinext 179.8 KB 179.8 KB ⚫ -0.0%

View detailed results and traces

🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head

@Boyeep
Boyeep force-pushed the fix/static-conditional-requests branch from ba20d9b to b66e664 Compare July 26, 2026 16:39
@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

@james-elicx Bonk workflow failed. Check the logs for details.

View workflow run · To retry, trigger Bonk again.

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

1 similar comment
@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

UnknownError: ProviderInitError

github run

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

UnknownError: ProviderInitError

github run

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

1 similar comment
@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the static-freshness / conditional-request work. This is a high-quality change: the RFC 9110 precondition ordering (If-Match → If-Unmodified-Since → If-None-Match → If-Modified-Since), weak-vs-strong comparison rules, whole-second date precision, and byte-range handling all look correct and are backed by thorough unit tests. Dev/prod parity is maintained across the Vite dev middleware, the cached fast path, the filesystem fallback in prod-server.ts, and the Worker asset path. A few small observations below — none blocking.

Comment thread packages/vinext/src/server/worker-utils.ts
Comment thread packages/vinext/src/server/prod-server.ts
Comment thread packages/vinext/src/server/http-conditional.ts
@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully.

Summary

I reviewed PR #2715 (fix(server): honor static freshness validators). This is a large, well-executed change adding RFC 9110 conditional-request and byte-range handling to vinext's static serving across all runtimes.

Verdict: high quality, no blocking issues.

What I verified:

  • Precondition ordering in http-conditional.ts matches RFC 9110 §13.2.2 (If-Match → If-Unmodified-Since → If-None-Match → If-Modified-Since) and returns 412/304/proceed correctly.
  • Entity-tag comparison — weak comparison for If-None-Match/If-Range date, strong for If-Match, correct handling of *, comma-in-opaque-tag, backslash-as-literal, and malformed tags.
  • HTTP-date parsing handles all three RFC formats including the RFC 850 50-year sliding window and calendar/weekday validation.
  • Byte ranges correctly handle suffix ranges, overflow beyond safe-integer, unsatisfiable → 416, and gate on If-Range + responseStatus === 200 + GET-only.
  • Dev/prod parity maintained across the Vite dev middleware (index.ts), the cached fast path and filesystem fallback (prod-server.ts), and the Worker asset path (worker-utils.ts).

Three minor, non-blocking observations posted inline:

  1. createStaticAssetRequest reuses sourceRequest as init for GET/HEAD, which also carries over the abort signal (likely intentional, worth confirming).
  2. resolveStaticValidators last-writer-wins on lowercased header names — fine given single-source headers, but worth a comment.
  3. The no-cache regex is correct; flagged only to keep its test coverage if touched.

github run

@james-elicx
james-elicx force-pushed the fix/static-conditional-requests branch from 90ed0e3 to d70435b Compare July 27, 2026 14:54
@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

1 similar comment
@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

UnknownError: ProviderInitError

github run

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

UnknownError: ProviderInitError

github run

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the static freshness/conditional-request work end to end. This is a high-quality change: the RFC 9110 §13.2.2 precondition ordering (If-Match → If-Unmodified-Since → If-None-Match → If-Modified-Since), weak-vs-strong entity-tag comparison, whole-second HTTP-date precision, the three HTTP-date wire formats (including the RFC 850 50-year sliding window with weekday/calendar validation), and single byte-range handling all look correct and are backed by thorough unit + integration tests. Dev/prod parity is maintained across the Vite dev middleware, the cached fast path, the filesystem slow path, and the Worker asset path. I ran the three new unit files locally (41 tests) — all green.

No blocking issues. A few small observations below; the earlier bot review already flagged the createStaticAssetRequest signal carry-over, the resolveStaticValidators last-writer-wins, and the no-cache regex, so I won't repeat those.

Comment thread packages/vinext/src/server/prod-server.ts
Comment thread packages/vinext/src/server/http-conditional.ts
Comment thread packages/vinext/src/server/http-date.ts
@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully.

Summary

I reviewed PR #2715 (fix(server): honor static freshness validators) and read the implementation files in full — http-conditional.ts, http-date.ts, http-range.ts, the prod-server.ts static-serving rewrite, static-file-cache.ts, and worker-utils.ts. I also ran the three new unit test files locally (41 tests, all passing).

Verdict: high quality, no blocking issues.

What I verified:

  • Precondition ordering matches RFC 9110 §13.2.2 (If-Match → If-Unmodified-Since → If-None-Match → If-Modified-Since) and returns 412/304/proceed correctly, including the 412-vs-304 split for unsafe methods.
  • Entity-tag comparison — strong for If-Match/If-Range, weak for If-None-Match; correct * wildcard, comma-in-opaque-tag, and malformed-list handling.
  • HTTP-date parsing handles all three RFC formats with weekday/calendar validation and the RFC 850 50-year sliding window.
  • Byte ranges — suffix ranges, safe-integer overflow, unsatisfiable → 416, gated on GET + responseStatus === 200 + strong If-Range.
  • Dev/prod parity across the fast path, slow path, and Worker asset path.

Three minor, non-blocking observations posted inline (deliberately avoiding the three already raised by the earlier bot review):

  1. Fast-path 416 omits Content-Type while slow-path 416 includes it — a small header-parity divergence between cached and filesystem paths.
  2. Redundant * wildcard check in evaluateStaticPreconditions that duplicates logic in matchesIfNoneMatch.
  3. A note to keep the second timestampFromHttpDateParts weekday-validation call intact in http-date.ts (correct as written, just fragile to future edits).

github run

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the static freshness / conditional-request work in full — http-conditional.ts, http-date.ts, http-range.ts, the prod-server.ts fast/slow-path rewrite, static-file-cache.ts, and worker-utils.ts. I re-ran the new unit suites locally (http-range 12, http-date 3, http-conditional 26, serve-static 62 — all green).

Verdict: high quality, no blocking issues. The RFC 9110 §13.2.2 precondition ordering, strong-vs-weak entity-tag comparison, whole-second HTTP-date handling (all three wire formats + RFC 850 sliding window), and single byte-range handling all look correct and are well-covered by tests. Dev/prod parity is maintained across the cached fast path, the filesystem slow path, and the Worker asset path.

Two new observations below (the earlier bot reviews already covered the signal carry-over, resolveStaticValidators last-writer-wins, the no-cache regex, the fast/slow 416 Content-Type divergence, and the redundant * check, so I won't repeat those). Both are behavioral/parity notes, not defects.

Comment thread packages/vinext/src/server/http-range.ts
Comment thread packages/vinext/src/server/worker-utils.ts Outdated
@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully.

Summary

I reviewed PR #2715 (fix(server): honor static freshness validators) end to end, reading all six implementation files and re-running the new unit suites locally (http-range 12, http-date 3, http-conditional 26, serve-static 62 — all 103 green).

Verdict: high quality, no blocking issues.

What I verified:

  • Precondition ordering in http-conditional.ts matches RFC 9110 §13.2.2 (If-Match → If-Unmodified-Since → If-None-Match → If-Modified-Since), including the 412-vs-304 split for unsafe methods and no-cache forcing full revalidation.
  • Entity-tag comparison — strong for If-Match/If-Range, weak for If-None-Match; correct * wildcard (only-member rule), comma-in-opaque-tag, backslash-as-literal, and malformed-list handling.
  • HTTP-date parsing — all three wire formats with weekday/calendar validation and the RFC 850 50-year sliding window.
  • Byte ranges — suffix ranges, safe-integer overflow, unsatisfiable → 416, correct inclusive end for both buffer subarray and fs.createReadStream({start,end}), gated on GET + responseStatus === 200 + strong If-Range.
  • Dev/prod parity — dev relies on Vite's built-in static middleware (handles ranges itself); prod fast path, slow path, and Worker asset path all covered.

Two new observations posted inline (deliberately avoiding the five already raised by earlier bot reviews):

  1. ifRangeAllowsRange weak-ETag behavior — every ETag vinext emits is weak, so ETag-based If-Range can never enable a 206 (RFC-correct, but a deliberate divergence from Next.js's strong-ETag send stack; worth a comment).
  2. Worker 206 + status-override — forwarding Range to Cloudflare ASSETS can yield a 206, and a middleware status-override would replace it with a non-206 status while keeping partial body/headers — a rare mismatch worth guarding.

Both are behavioral/parity notes, not defects.

github run

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the static freshness / conditional-request work end to end — http-conditional.ts, http-date.ts, http-range.ts, the prod-server.ts fast/slow-path rewrite, static-file-cache.ts, worker-utils.ts, and the createStaticAssetRequest wiring in app-router-entry.ts.

Verdict: high quality, no blocking issues. RFC 9110 §13.2.2 precondition ordering (If-Match → If-Unmodified-Since → If-None-Match → If-Modified-Since), the 412-vs-304 split for unsafe methods, strong-vs-weak entity-tag comparison, whole-second HTTP-date precision across all three wire formats (including the RFC 850 50-year sliding window with weekday/calendar validation), and single byte-range handling (suffix ranges, safe-integer overflow, 416, inclusive end for both subarray and createReadStream) all look correct and are backed by thorough unit + integration tests. Dev/prod parity is maintained across the cached fast path, the filesystem slow path, and the Worker ASSETS path.

The prior bot reviews already covered the notable observations (signal carry-over, resolveStaticValidators last-writer-wins, the no-cache regex, fast/slow 416 Content-Type divergence, the redundant * check, the always-weak-ETag If-Range trade-off, and the Worker 206 status-override edge). I confirmed all of those and won't repeat them. One new parity note below — not a defect.

Comment thread packages/vinext/src/server/prod-server.ts
@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully.

Summary

I reviewed PR #2715 (fix(server): honor static freshness validators) end to end, reading all the implementation files in full (http-conditional.ts, http-date.ts, http-range.ts, the prod-server.ts fast/slow-path rewrite, static-file-cache.ts, worker-utils.ts) and the createStaticAssetRequest wiring in app-router-entry.ts. I also validated the asctime regex day-parsing edge cases directly.

Verdict: high quality, no blocking issues.

What I verified:

  • Precondition ordering matches RFC 9110 §13.2.2, including the 412-vs-304 split for unsafe methods and no-cache forcing full revalidation.
  • Entity-tag comparison — strong for If-Match/If-Range, weak for If-None-Match; correct * wildcard, comma-in-opaque-tag, backslash-as-literal, malformed-list handling.
  • HTTP-date parsing — all three wire formats with weekday/calendar validation and the RFC 850 50-year sliding window.
  • Byte ranges — suffix ranges, safe-integer overflow, unsatisfiable → 416, inclusive end for both buffer subarray and createReadStream, gated on GET + responseStatus === 200 + strong If-Range.
  • Dev/prod parity across the cached fast path, filesystem slow path, and Worker ASSETS path.

I posted one new parity note (not a defect): the identity/full response advertises Accept-Ranges: bytes even on a compressed-variant response, while a subsequent range request always serves the identity representation from entry.original — a benign representation mismatch worth a one-line comment. I confirmed and deliberately did not repeat the seven observations earlier bot reviews already raised (signal carry-over, last-writer-wins validators, the no-cache regex, fast/slow 416 Content-Type divergence, the redundant * check, the always-weak-ETag If-Range trade-off, and the Worker 206 status-override edge).

github run

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the static-freshness/conditional-request implementation end to end (http-conditional.ts, http-date.ts, http-range.ts, the prod-server.ts fast/slow rewrite, static-file-cache.ts, worker-utils.ts) and ran the three new unit suites locally (41 tests, all green).

Verdict: high quality, no blocking issues. RFC 9110 §13.2.2 precondition ordering, strong-vs-weak entity-tag comparison, whole-second HTTP-date parsing across all three wire formats (incl. the RFC 850 50-year sliding window with weekday/calendar validation), and single byte-range handling (suffix ranges, safe-integer overflow, 416, inclusive end for both subarray and createReadStream, gated on GET + responseStatus === 200 + strong If-Range) all look correct. Dev/prod parity is maintained across the cached fast path, the filesystem slow path, and the Worker ASSETS path.

I confirmed the observations earlier reviews already covered (signal carry-over, resolveStaticValidators last-writer-wins, the no-cache regex, the always-weak-ETag If-Range trade-off, the Worker 206 status-override edge, and the Accept-Ranges on compressed responses) and won't repeat them. One new, minor parity note below — not a defect.

Comment thread packages/vinext/src/server/prod-server.ts Outdated
@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully.

Summary

I reviewed PR #2715 (fix(server): honor static freshness validators) end to end — reading all six implementation files (http-conditional.ts, http-date.ts, http-range.ts, the prod-server.ts fast/slow-path rewrite, static-file-cache.ts, worker-utils.ts) plus the createStaticAssetRequest wiring in app-router-entry.ts, and running the three new unit suites locally (41 tests, all green).

Verdict: high quality, no blocking issues.

What I verified:

  • Precondition ordering in http-conditional.ts:127 matches RFC 9110 §13.2.2 (If-Match → If-Unmodified-Since → If-None-Match → If-Modified-Since), including the 412-vs-304 split for unsafe methods and no-cache forcing full revalidation.
  • Entity-tag comparison — strong for If-Match/If-Range, weak for If-None-Match; correct * wildcard, comma-in-opaque-tag, backslash-as-literal, and malformed-list rejection.
  • HTTP-date parsing — all three wire formats with weekday/calendar validation and the RFC 850 50-year sliding window.
  • Byte ranges (http-range.ts) — suffix ranges, safe-integer overflow, unsatisfiable → 416, inclusive end for both buffer subarray(start, end+1) and createReadStream({start, end}), gated on GET + responseStatus === 200 + strong If-Range.
  • HEAD/Range correctly ignored (requestRange is undefined for non-GET), matching RFC.
  • Dev/prod parity across the cached fast path, filesystem slow path, and Worker ASSETS path.

One new, non-blocking observation posted inline:

  • The 412 responses have the same fast/slow-path Content-Type + Accept-Ranges divergence that the recently-merged a361cfa fixed for 416s. Fast-path 412 omits both headers; slow-path 412 (via baseHeaders) includes them. RFC-legal either way, but worth aligning for consistency now that 416 was aligned. Posted with a suggestion.

I deliberately confirmed and did not repeat the observations earlier bot reviews already raised (signal carry-over, resolveStaticValidators last-writer-wins, the no-cache regex, the always-weak-ETag If-Range trade-off, the Worker 206 status-override edge, and Accept-Ranges on compressed responses).

github run

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the static-freshness / conditional-request implementation end to end — http-conditional.ts, http-date.ts, http-range.ts, the prod-server.ts fast/slow-path rewrite, static-file-cache.ts, worker-utils.ts, and the createStaticAssetRequest wiring in app-router-entry.ts.

Verdict: high quality, no blocking issues. The RFC 9110 §13.2.2 precondition ordering (If-Match → If-Unmodified-Since → If-None-Match → If-Modified-Since), the 412-vs-304 split for unsafe methods, strong-vs-weak entity-tag comparison, whole-second HTTP-date handling across all three wire formats (including the RFC 850 50-year sliding window with weekday/calendar validation), and single byte-range handling (suffix ranges, safe-integer overflow, 416, inclusive end for both subarray and createReadStream, gated on GET + responseStatus === 200 + strong If-Range) all look correct and are backed by thorough tests. HEAD/Range is correctly ignored via requestRange = req.method === "GET" ? …. Dev/prod parity is maintained across the cached fast path, the filesystem slow path, and the Worker ASSETS path. I confirmed the 412 fast/slow-path Content-Type/Accept-Ranges alignment from 1dee6f8 is in place.

I confirmed the observations earlier reviews already raised (signal carry-over, resolveStaticValidators last-writer-wins, the no-cache regex, the always-weak-ETag If-Range trade-off, the Worker 206 status-override edge, Accept-Ranges on compressed responses, and the 412 alignment) and won't repeat them. One new parity note below — not a defect.

Comment thread packages/vinext/src/server/prod-server.ts Outdated
@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully.

Summary

I reviewed PR #2715 (fix(server): honor static freshness validators) end to end — reading all the implementation files in full (http-conditional.ts, http-date.ts, http-range.ts, the prod-server.ts fast/slow-path rewrite, static-file-cache.ts, worker-utils.ts) plus the createStaticAssetRequest wiring in app-router-entry.ts.

Verdict: high quality, no blocking issues.

What I verified:

  • Precondition ordering matches RFC 9110 §13.2.2, including the 412-vs-304 split for unsafe methods and no-cache forcing revalidation.
  • Entity-tag comparison — strong for If-Match/If-Range, weak for If-None-Match; correct *, comma-in-opaque-tag, backslash-as-literal, malformed-list handling.
  • HTTP-date parsing — all three wire formats, weekday/calendar validation, RFC 850 50-year sliding window. The asctime two-space single-digit day case parses correctly.
  • Byte ranges — suffix ranges, safe-integer overflow → unsatisfiable, inclusive end for both buffer subarray and createReadStream, gated on GET + status 200 + strong If-Range. HEAD/Range correctly ignored.
  • Dev/prod parity across fast path, slow path, and Worker ASSETS path. Confirmed the earlier 412 alignment from 1dee6f8 is in place.
  • mergeVaryHeader returns a copy (no shared-object mutation), and the NaN-mtime override path correctly disables date-based If-Range.

One new parity note posted inline (not a defect): the slow-path 304 still emits the full baseHeaders (Content-Type, Accept-Ranges, Last-Modified), while the fast-path 304 uses the trimmed notModifiedHeaders. This PR widened the gap by adding Accept-Ranges to baseHeaders, and there's an existing test literally named "304 response excludes Content-Type per RFC 9110" that only covers the fast path. Worth aligning the 304 paths the same way you already aligned 412 and 416.

I deliberately did not repeat the seven observations earlier bot reviews already raised.

github run

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the static-freshness / conditional-request work end to end — http-conditional.ts, http-date.ts, http-range.ts, the prod-server.ts fast/slow-path rewrite, static-file-cache.ts, worker-utils.ts, and the createStaticAssetRequest wiring in app-router-entry.ts. Ran the three new unit suites locally (41 tests, all green).

Verdict: high quality, no blocking issues.

What I verified:

  • Precondition ordering (http-conditional.ts:127) matches RFC 9110 §13.2.2 (If-Match → If-Unmodified-Since → If-None-Match → If-Modified-Since), the 412-vs-304 split for unsafe methods, and no-cache forcing full revalidation.
  • Entity-tag comparison — strong for If-Match/If-Range, weak for If-None-Match; correct * wildcard, comma-in-opaque-tag, backslash-as-literal, and malformed-list rejection.
  • HTTP-date parsing — all three wire formats with weekday/calendar validation and the RFC 850 50-year sliding window.
  • Byte ranges — suffix ranges, safe-integer overflow → unsatisfiable, 416, inclusive end for both buffer subarray(start, end+1) and createReadStream({start, end}), gated on GET + responseStatus === 200 + strong If-Range. HEAD/Range correctly ignored via requestRange = req.method === "GET" ? ….
  • Worker pathassetResponse.status !== 206 guard on the status override is correct, and 416 (a 4xx, so !ok) is preserved rather than masked.
  • Fast/slow-path header parity — I confirmed the 412 (baseHeaders vs notModifiedHeaders + Content-Type + Accept-Ranges), 416, and 304 (trimmed notModifiedBaseHeaders on the slow path) divergences flagged in earlier review rounds are all now aligned in the follow-up commits (a361cfa, 1dee6f8, 9734c04).

One new, non-blocking observation posted inline — a theoretical RFC 850 leap-year edge case. Everything else in this PR is solid and thoroughly tested.

Comment thread packages/vinext/src/server/http-date.ts
@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully.

Summary

I reviewed PR #2715 (fix(server): honor static freshness validators) end to end — reading all six implementation files (http-conditional.ts, http-date.ts, http-range.ts, the prod-server.ts fast/slow-path rewrite, static-file-cache.ts, worker-utils.ts) plus the createStaticAssetRequest wiring in app-router-entry.ts, and running the three new unit suites locally (41 tests, all green).

Verdict: high quality, no blocking issues.

What I verified:

  • Precondition ordering matches RFC 9110 §13.2.2, including the 412-vs-304 split for unsafe methods and no-cache forcing full revalidation.
  • Entity-tag comparison — strong for If-Match/If-Range, weak for If-None-Match; correct wildcard, comma-in-opaque-tag, backslash-as-literal, malformed-list handling.
  • HTTP-date parsing — all three wire formats with weekday/calendar validation and the RFC 850 sliding window.
  • Byte ranges — suffix ranges, safe-integer overflow, 416, inclusive end, gated on GET + status 200 + strong If-Range; HEAD/Range correctly ignored.
  • Worker path — the status !== 206 override guard is correct, and 416 responses are preserved.
  • Fast/slow-path header parity — confirmed the 412/416/304 divergences flagged in earlier review rounds are now all aligned via follow-up commits (a361cfa, 1dee6f8, 9734c04).

I posted one new non-blocking observation inline: a theoretical RFC 850 leap-year century-boundary edge case in http-date.ts:61 (only reachable with year 2100+, the obsolete RFC 850 format, and a Feb-29 date — academic, fine to leave as-is).

The seven observations from prior bot review rounds (signal carry-over, last-writer-wins validators, the no-cache regex, the always-weak-ETag If-Range trade-off, the Worker 206 status-override edge, Accept-Ranges on compressed responses, and the header-parity nits) I confirmed and deliberately did not repeat — the parity nits in particular are now resolved in the committed follow-ups.

github run

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the static-freshness / conditional-request work end to end and ran the new unit suites locally (http-range 12, http-date 4, http-conditional 26, serve-static 62 — all green).

Verdict: high quality, no blocking issues.

What I verified:

  • Precondition ordering (http-conditional.ts:127) matches RFC 9110 §13.2.2 (If-Match → If-Unmodified-Since → If-None-Match → If-Modified-Since), the 412-vs-304 split for unsafe methods, and request Cache-Control: no-cache forcing full revalidation (matches the send/fresh stack Next.js uses).
  • Entity-tag comparison — strong for If-Match/If-Range, weak for If-None-Match; correct * wildcard, comma-in-opaque-tag, backslash-as-literal, and malformed-list rejection.
  • HTTP-date parsing — all three wire formats with weekday/calendar validation, the RFC 850 50-year sliding window, and lenient (safe) asctime day parsing.
  • Byte ranges — suffix ranges, safe-integer overflow → unsatisfiable, 416, inclusive end for both buffer subarray(start, end+1) and createReadStream({start, end}), gated on GET + responseStatus === 200 + strong If-Range. HEAD/Range correctly ignored via requestRange = req.method === "GET" ? ….
  • Range/omitBody/HEAD interaction — the 206/416 paths never run for no-body statuses (they gate on 200) and never run for HEAD (undefined requestRange), so no missing omitBody guard.
  • Worker path — the assetResponse.status !== 206 override guard is correct; 416 (a 4xx) is preserved via !ok. mergeVaryHeader returns a copy (no shared-object mutation).
  • Fast/slow-path header parity — the 412/416/304 divergences flagged in prior rounds are aligned in the follow-up commits.

The observations from prior review rounds (signal carry-over, resolveStaticValidators last-writer-wins, the no-cache regex, the always-weak-ETag If-Range trade-off, the Worker 206 status-override edge, Accept-Ranges on compressed responses, the header-parity nits, and the RFC 850 leap-day edge) I confirmed and deliberately did not repeat. One small new note below — not a defect.

Comment thread packages/vinext/src/server/http-date.ts
@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully.

Summary

I reviewed PR #2715 (fix(server): honor static freshness validators) end to end — reading all six implementation files (http-conditional.ts, http-date.ts, http-range.ts, the prod-server.ts fast/slow-path rewrite, static-file-cache.ts, worker-utils.ts) plus the createStaticAssetRequest wiring in app-router-entry.ts, and running the new unit suites locally (44 tests + 62 serve-static, all green).

Verdict: high quality, no blocking issues.

What I verified:

  • Precondition ordering matches RFC 9110 §13.2.2, the 412-vs-304 split for unsafe methods, and request Cache-Control: no-cache forcing revalidation.
  • Entity-tag comparison — strong for If-Match/If-Range, weak for If-None-Match; correct wildcard, comma-in-tag, backslash-as-literal, malformed-list handling.
  • HTTP-date parsing — all three wire formats with weekday/calendar validation and the RFC 850 sliding window.
  • Byte ranges — suffix ranges, safe-integer overflow, 416, inclusive end, gated on GET + status 200 + strong If-Range; HEAD/Range correctly ignored.
  • Range/omitBody/HEAD interaction — confirmed the 206/416 paths can't collide with no-body statuses or HEAD, so no missing guards.
  • Worker path — the 206 override guard and 416 preservation are correct; mergeVaryHeader returns a copy.
  • Fast/slow-path header parity — the 412/416/304 divergences from earlier rounds are aligned in follow-up commits.

I posted one new, non-blocking note: the asctime branch leniently accepts a zero-padded two-digit day (RFC 9110 asctime space-pads), which is safe since it only parses incoming validators and never emits one — flagged purely so it isn't mistaken for strict conformance.

I deliberately confirmed and did not repeat the ~eight observations from the prior review rounds.

github run

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the full implementation end to end (http-conditional.ts, http-date.ts, http-range.ts, the prod-server.ts fast/slow-path rewrite, static-file-cache.ts, worker-utils.ts, and the createStaticAssetRequest wiring in app-router-entry.ts) and re-ran the three new unit suites locally (42 tests, all green).

Verdict: high quality, no blocking issues. The RFC 9110 §13.2.2 precondition ordering, weak/strong entity-tag comparison, three HTTP-date wire formats with the RFC 850 sliding window, and single byte-range handling (suffix, safe-integer overflow, 416, inclusive end, gated on GET/HEAD + status 200 + strong If-Range) all look correct and are thoroughly tested. Fast/slow/Worker parity is maintained.

One clarification for the record on the newest commit (match weak static etags for If-Match): treating W/"asset" as matching "asset" for If-Match diverges from RFC 9110 §13.1.1's strong-comparison requirement, but it correctly matches Next.js's send stack, whose isPreconditionFailure compares match === etag || match === 'W/'+etag || 'W/'+match === etag. So the divergence is deliberate and parity-correct — good call, worth a one-line comment citing send so it isn't "fixed" later.

Three small, non-blocking observations below. The many items raised across the prior review rounds (signal carry-over, last-writer-wins validators, the no-cache regex, always-weak-ETag If-Range, Worker 206 override, Accept-Ranges on compressed responses, the 412/416/304 header-parity nits, and the RFC 850 leap-day edge) I confirmed and won't repeat.

Comment thread packages/vinext/src/server/http-conditional.ts
Comment thread packages/vinext/src/server/http-range.ts
Comment thread packages/vinext/src/server/prod-server.ts
@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully.

Summary

I reviewed PR #2715 (fix(server): honor static freshness validators) end to end — reading all the implementation files (http-conditional.ts, http-date.ts, http-range.ts, the prod-server.ts fast/slow-path rewrite, static-file-cache.ts, worker-utils.ts) plus the createStaticAssetRequest wiring in app-router-entry.ts, and re-running the three new unit suites locally (42 tests, all green).

Verdict: high quality, no blocking issues.

What I verified:

  • Precondition ordering matches RFC 9110 §13.2.2 (If-Match → If-Unmodified-Since → If-None-Match → If-Modified-Since), the 412-vs-304 split for unsafe methods, and no-cache forcing revalidation.
  • Entity-tag comparison — the matchesIfMatch weak/strong equivalence is a deliberate divergence from RFC 9110 §13.1.1 that correctly matches Next.js's send library (isPreconditionFailure), which validates the newest commit's approach.
  • HTTP-date parsing — all three wire formats with weekday/calendar validation and the RFC 850 sliding window.
  • Byte ranges — suffix, safe-integer overflow, 416, inclusive end, gated on GET/HEAD + status 200 + strong If-Range.
  • Fast/slow/Worker parity, including the 206 status-override guard.

I posted three small, non-blocking observations that hadn't been raised in prior rounds:

  1. A comment citing send on matchesIfMatch so the intentional weak-If-Match parity isn't "corrected" later.
  2. The RFC 9110 §13.1.5 strong-date-validator guard for If-Range dates is intentionally omitted (sub-second window only) — worth a note.
  3. The Last-Modified-as-array override path yields NaN mtime (safe fallback, untested branch).

I confirmed and deliberately did not repeat the ~10 observations from the earlier review rounds, which are all either resolved in follow-up commits or non-defects.

github run

@james-elicx
james-elicx merged commit 3d1ab6b into cloudflare:main Jul 27, 2026
58 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