fix(serve-static): check the response (not request) for an existing content-length#1391
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughserveStatic now checks the response headers for an existing ChangesStatic File Content-Length Handling
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ontent-length serveStatic only sets content-length when one isn't already present, the same way it guards content-type, content-encoding and last-modified. Those three check event.res.headers, but the content-length guard checked event.req.headers — the request's content-length, which has no bearing on the response. A GET/HEAD request almost never carries a content-length, so the guard is accidentally true in normal use and the derived size is still applied, which is why the bug is invisible day to day. But a content-length deliberately set via options.headers is silently overwritten by meta.size, and a request that does carry a content-length wrongly suppresses the response header. Switches the guard to event.res.headers, matching the sibling guards. Adds a regression test asserting an explicit response content-length is preserved.
a70ab60 to
4a1b971
Compare
pi0x
left a comment
There was a problem hiding this comment.
Note: this review was performed by AI agents (Claude Code) on behalf of the maintainer, in two independent passes.
Pass 1 reviewed the diff for correctness, edge cases, and test coverage. Pass 2 (a fresh agent, adversarial by design) independently re-read the diff, checked for merge conflicts/CI status, and tried to find a reason to block approval before this review was posted. Both passes agree this change is correct, adequately tested, and safe to merge.
Caveat: this repo's real CI workflow (lint + build + vitest) requires maintainer approval to run on fork PRs and has not executed on this PR yet — only automated third-party checks (CodeRabbit, Socket Security) have run. Please trigger/approve the CI workflow before merging.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
What
In
serveStatic(src/utils/static.ts), thecontent-lengthresponse header is set frommeta.sizeonly when one isn't already present. That guard checks the request headers:
Every sibling guard in the same function checks the response headers instead —
content-type,content-encoding, andlast-modifiedare all set onlyif (!event.res.headers.get(...)). This bringscontent-lengthinto line:Why (asymmetric — easy to miss in review)
A GET/HEAD request almost never carries a
content-lengthof its own, so!event.req.headers.get("content-length")is "accidentally true" in normal use and the derived sizeis still applied — the function looks correct in every ordinary test. The bug only surfaces in two edge
cases:
content-lengthdeliberately set by the caller viaoptions.headersis silently overwritten bymeta.size(the request guard never sees the response header that's already there).content-length(e.g. behind a proxy, or a GET with a body) wronglysuppresses the response
content-length.Because the common path is unaffected, a reviewer scanning the logic sees
event.req.headersandevent.res.headersa line apart and the slip reads as intentional — until the three sibling guards arelined up next to it.
Safety / blast radius
content-length⇒ identical result; allfour existing
content-lengthassertions intest/static.test.tsstay green).content-lengthinto line with the function's own "set only when absent" contract.Testing
content-length(viaoptions.headers) must bepreserved, not overwritten by
meta.size. It fails on the current code (returns the derived18instead of the explicit
999) on both thewebandnodematrix targets, and passes with the fix.vitest run+tsc --noEmit).Summary by CodeRabbit
Bug Fixes
content-lengthheader instead of recalculating it.Tests
HEADresponses keep a configuredcontent-lengthvalue unchanged.