Skip to content

fix(cors): set single-valued CORS headers instead of appending#1466

Merged
pi0 merged 1 commit into
mainfrom
fix/cors-set-headers
Jul 15, 2026
Merged

fix(cors): set single-valued CORS headers instead of appending#1466
pi0 merged 1 commit into
mainfrom
fix/cors-set-headers

Conversation

@pi0x

@pi0x pi0x commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Applying CORS headers more than once (e.g. middleware plus handler) duplicated single-valued response headers, producing invalid values like *, * for access-control-allow-origin, access-control-allow-methods, access-control-max-age, and access-control-allow-credentials.

This switches appendCorsHeaders/appendCorsPreflightHeaders to use .set for CORS response headers, keeping .append only for the legitimately multi-valued vary header. Added regression tests that apply CORS twice and assert single values.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed CORS responses to prevent duplicate single-value headers when headers are applied more than once.
    • Preserved multiple Vary header values correctly for preflight and standard requests.
  • Tests

    • Added coverage verifying consistent CORS headers across repeated applications.

Applying CORS headers more than once (e.g. middleware + handler) could
duplicate single-valued response headers, producing invalid values like
`*, *` for `access-control-allow-origin`, `access-control-allow-methods`,
`access-control-max-age`, `access-control-allow-credentials`, etc.

Use `.set` for CORS response headers and keep `.append` only for the
legitimately multi-valued `vary` header.

Co-Authored-By: Claude Fable 5 <[email protected]>
@pi0x
pi0x requested a review from pi0 as a code owner July 14, 2026 12:35

@pi0x pi0x left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Review: LGTM (posting as comment — GitHub blocks self-approval on own PR)

The change is correct and well-targeted.

Correctness

  • All single-valued CORS response headers now use .set: access-control-allow-origin, access-control-allow-methods, access-control-allow-credentials, access-control-allow-headers, access-control-expose-headers, access-control-max-age. Each is produced by the create* helpers as a single fully-computed value (comma-joined lists built in one shot), so .set is the right semantics — including for allow-headers/expose-headers, where a repeated application should replace rather than concatenate.
  • vary correctly stays on .append (legitimately multi-valued; distinct code paths contribute different vary tokens).
  • Both res.headers and res.errHeaders are handled identically, matching prior behavior.
  • Single-application output (headers emitted and their values) is unchanged — verified by the existing unit tests passing.

API/types: setCorsHeaders is a non-exported internal helper; no public API or type surface change.

Tests: The two regression tests apply CORS twice and assert single values, directly covering the *, * bug.

Verification: pnpm vitest run test/unit/cors.test.ts → 46 passed; pnpm lint clean.

Minor, non-blocking: Applying preflight twice still duplicates vary tokens (e.g. origin, origin). Harmless/valid per HTTP and out of scope for this fix; noting in case dedup is later desired.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6b07af87-63e9-45b5-b1aa-4f20144fd0a4

📥 Commits

Reviewing files that changed from the base of the PR and between 2264316 and 618471c.

📒 Files selected for processing (2)
  • src/utils/cors.ts
  • test/unit/cors.test.ts

📝 Walkthrough

Walkthrough

CORS header helpers now centralize response updates, replacing single-valued headers instead of appending duplicates while continuing to append vary. Unit tests cover repeated preflight and normal-request applications.

Changes

CORS header idempotency

Layer / File(s) Summary
Centralized CORS header writing
src/utils/cors.ts
Preflight and normal CORS handlers use setCorsHeaders, which sets single-valued headers and appends vary in both response header stores.
Repeated-application tests
test/unit/cors.test.ts
Tests verify that applying preflight and normal CORS headers twice does not duplicate single-valued headers.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • h3js/h3#1352: Modifies the same CORS header application paths.
  • h3js/h3#1396: Changes CORS header construction and merging in related utilities.
  • h3js/h3#1456: Refactors behavior in the same preflight and CORS header functions.

Suggested reviewers: francisjohnjohnston-web

Poem

I’m a rabbit with headers to set,
No duplicate carrots are met.
vary hops along,
Single values stay strong,
Twice applied, they’re tidy yet.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: switching single-valued CORS headers from append to set.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cors-set-headers

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pi0
pi0 merged commit 63e4b98 into main Jul 15, 2026
9 checks passed
@pi0
pi0 deleted the fix/cors-set-headers branch July 15, 2026 08:06
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