fix(writeEarlyHints): normalize Link key to prevent hanging with Node.js#1385
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 (1)
📝 WalkthroughWalkthrough
ChangesEarly-hints callback normalization
Estimated code review effort: 2 (Simple) | ~15 minutes Possibly related PRs
Suggested reviewers: Related issues: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ 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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/utils/response.ts`:
- Around line 121-125: The loop in src/utils/response.ts currently clobbers
prior Link values when normalizing keys: for case where name.toLowerCase() ===
"link" and name !== "link" you should merge the new value into
normalizedHints.link instead of overwriting it; locate the for (const [name,
value] of Object.entries(hints)) block and change the assignment to
append/concatenate the incoming value to normalizedHints.link (create an array
or comma-joined string if needed) while still deleting the original case-variant
key so all case-variant Link hints are preserved.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b8f62ae7-7197-4661-b16b-3c5c8040e4e1
📒 Files selected for processing (1)
src/utils/response.ts
Node.js writeEarlyHints only reads hints.link (lowercase) and returns early without invoking the callback when the 'link' property is missing. Since HTTP headers are case-insensitive, callers may pass 'Link' (capital L), causing the native method to silently return and the promise to never resolve. Fix: normalize the 'link' key before calling the native writeEarlyHints, and return immediately (no promise) when no link hints are present. Fixes h3js#1383
d68edbf to
70a7e28
Compare
|
Note: this analysis was performed by an AI agent (Claude Code) on behalf of the maintainer. This looks like the most correct fix for the Would you be open to adding a regression test that reproduces the exact #1383 case ( |
The previous fix normalized the Link key but shipped without test coverage for the Node.js native path it targets (the existing test was skipIf(target === 'node')). Add matrix regression tests that race writeEarlyHints against a timer inside a real Node handler, proving the promise resolves promptly instead of hanging when the resolved link value is missing or empty. Also harden the normalization to merge every case-variant of the link key (e.g. both 'link' and 'Link') into a single value instead of letting the last-processed key clobber the others, and to treat empty strings / empty arrays as 'no link' (matching Node's own callback-skipping behavior) so those inputs no longer hang. Co-Authored-By: Claude Opus <[email protected]>
|
Pushed Disclosure: this commit was authored by an AI agent (Claude Code / Claude Opus), not a human, and pushed via the maintainer-can-modify permission on this PR. Please review it as you would any change. Thanks @mixelburg for the accurate root-cause diagnosis — that Node's native What this commit adds on top of your fix:
|
The empty-value filter and case-insensitive link normalization added for the Node native path were not applied to the web/CDN fallback, so falsy link values appended a malformed empty `Link:` header on non-Node runtimes. Share a single normalization step between both paths, drop falsy link values in the fallback, and return a resolved Promise (not sync undefined) on the Node empty-link early return for consistency. Add fallback tests that assert the resulting Link header. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Only construct the normalized hints object on the Node path where it is actually passed to the native writeEarlyHints; the CDN/web fallback now uses the collected link values directly without allocating a discarded map. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
What
Fixes
writeEarlyHintsnever resolving (hanging indefinitely) when called with aLinkheader using a non-lowercase key (e.g.,{ Link: '...' }).Closes #1383.
Why
Node.js's native
res.writeEarlyHints(hints, cb)only readshints.link(lowercase). Iflinkis missing or undefined, it returns early without invoking the callback. Since HTTP headers are case-insensitive, users naturally pass{ Link: '...' }— causing the h3 function to hang forever because the Promise never resolves.How
Before calling the native
writeEarlyHints:Link/LINK/ etc. key to lowercaselinklinkproperty exists after normalization, return immediately (no need for a Promise)Reproduction
Root Cause
Node.js source (
lib/_http_server.js):Summary by CodeRabbit
link/Linkvariations, dropping falsy/empty entries, and preventing hangs when no validlinkhints are provided. The CDN/web fallback now emits only the collected, truthylinkheader values.writeEarlyHintsresolves promptly (including{}and emptylink/Linkcases), and verified correct header output when mixed values are provided and when bothlinkandLinkmust be merged.