Skip to content

perf(cookie): avoid quadratic chunked cookie parsing and header rebuilds#1472

Merged
pi0 merged 3 commits into
mainfrom
perf/cookie
Jul 15, 2026
Merged

perf(cookie): avoid quadratic chunked cookie parsing and header rebuilds#1472
pi0 merged 3 commits into
mainfrom
perf/cookie

Conversation

@pi0x

@pi0x pi0x commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Minimal alternative to #1368 — same perf improvement for the chunked-cookie path used by sessions, without the WeakMap caches or set-cookie state tracking. Credit to @trivikr for identifying the issue and the original implementation (also co-authored on the commit).

setCookie() rebuilt (delete → parseSetCookie each → re-append) the full set-cookie header list on every write, and getChunkedCookie() reparsed the full request cookie header once per chunk — making large chunked session reads/writes quadratic in chunk count.

Changes

  • Read path: getChunkedCookie() calls parseCookies() once and indexes into the result instead of calling getCookie() (a full reparse) per chunk.
  • Write path: setCookie() appends directly when no existing set-cookie header starts with name= — a cheap conservative check that skips the parse/rebuild entirely. The dedupe rebuild still runs on an actual name collision, so overwrite semantics are unchanged. Chunk cookie names are always unique, so setChunkedCookie() always takes the fast path.

A side benefit of the fast path: set-cookie headers written directly to res.headers (e.g. by middleware) are no longer dropped when a later setCookie() call appends an unrelated cookie (previously the rebuild discarded any header parseSetCookie couldn't parse).

Tests

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Preserved externally provided set-cookie headers added directly to the response when overwriting a cookie with the same name.
    • Improved chunked cookie reading/writing logic to maintain the same chunk values and numbering.
  • Tests
    • Added coverage ensuring externally provided set-cookie headers aren’t removed during cookie updates.
    • Added performance-oriented tests verifying efficient chunked cookie parsing and correct Set-Cookie chunk output.

Read path: getChunkedCookie now parses the request cookie header once
and indexes into the result instead of reparsing it per chunk.

Write path: setCookie appends directly when no existing set-cookie
header shares the cookie name, skipping the delete/reparse/re-append
rebuild. The dedupe rebuild only runs on an actual name collision.

Minimal alternative to #1368.

Co-authored-by: Trivikram Kamat <[email protected]>
Co-Authored-By: Claude Fable 5 <[email protected]>
@pi0x
pi0x requested a review from pi0 as a code owner July 15, 2026 08:50
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 20c0d3f7-e68d-4e11-a911-b9f024840de8

📥 Commits

Reviewing files that changed from the base of the PR and between 6354553 and 051642f.

📒 Files selected for processing (1)
  • test/unit/cookie-perf.test.ts

📝 Walkthrough

Walkthrough

setCookie preserves unrelated manually appended response cookies. getChunkedCookie reuses one parsed cookie map for main and chunk lookups, with tests covering behavior and parsing call counts.

Changes

Cookie handling

Layer / File(s) Summary
Response cookie preservation
src/utils/cookie.ts, test/cookies.test.ts
setCookie appends cookies with new names without the previous merge path, while tests verify unrelated manually appended headers remain present during overwrites.
Chunked-cookie parsing optimization
src/utils/cookie.ts, test/unit/cookie-perf.test.ts
getChunkedCookie reads the main cookie and chunks from one parsed map, with tests validating concatenated values and parser call counts.

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

Possibly related PRs

  • h3js/h3#1462: Both modify setCookie Set-Cookie preservation and deduplication behavior.

Suggested reviewers: pi0

Poem

A bunny hops through cookies bright,
Keeping headers tucked just right.
Chunks align in one quick read,
Tests confirm the parsing speed.
Hop, hop—no crumbs are lost tonight!

🚥 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 accurately summarizes the main performance change to chunked cookie parsing and Set-Cookie header updates.
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 perf/cookie

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/cookies.test.ts (1)

142-142: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Use ctx.fetch for cross-runtime URL resolution.

This test calls t.fetch("/"), but the repository requires ctx.fetch so URL resolution works consistently in both web and node test contexts.

As per coding guidelines, test/**/*.test.ts must use ctx.fetch for URL resolution that works in both web and node test contexts.

🤖 Prompt for 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.

In `@test/cookies.test.ts` at line 142, Update the test request in the affected
cookie test from t.fetch("/") to ctx.fetch("/"), preserving the existing path
and assertions so URL resolution works consistently across web and Node test
contexts.

Source: Coding guidelines

🤖 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 `@test/unit/cookie-perf.test.ts`:
- Around line 17-21: Refactor the “cookie performance” test suite to use
describeMatrix for both web and node modes instead of describe. Initialize a
fresh H3 instance and real H3Event in beforeEach, track unhandled errors through
ctx.errors, and assert them in afterEach; update the tests to use these
instances and remove event as any casts while preserving the existing cookie
assertions.

---

Nitpick comments:
In `@test/cookies.test.ts`:
- Line 142: Update the test request in the affected cookie test from
t.fetch("/") to ctx.fetch("/"), preserving the existing path and assertions so
URL resolution works consistently across web and Node test contexts.
🪄 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: 2bcb9c5a-b924-47a2-95cf-8070c46dcd89

📥 Commits

Reviewing files that changed from the base of the PR and between c97ed61 and 16909ce.

📒 Files selected for processing (3)
  • src/utils/cookie.ts
  • test/cookies.test.ts
  • test/unit/cookie-perf.test.ts

Comment on lines +17 to +21
describe("cookie performance", () => {
beforeEach(() => {
parseCookieSpy.mockClear();
parseSetCookieSpy.mockClear();
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Align test suite with cross-runtime testing guidelines.

The current test suite uses a standard describe block and manually mocks the event object. As per coding guidelines for test/**/*.test.ts, tests must:

  • Use describeMatrix to execute in both web and node modes.
  • Ensure each test has a fresh H3 instance via beforeEach setup.
  • Track unhandled errors with ctx.errors and auto-assert them in afterEach.

Refactoring this suite to use the matrix testing utilities and real H3Event instances will properly validate the cookie optimizations across runtimes and eliminate the need for casting event as any in your assertions.

🤖 Prompt for 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.

In `@test/unit/cookie-perf.test.ts` around lines 17 - 21, Refactor the “cookie
performance” test suite to use describeMatrix for both web and node modes
instead of describe. Initialize a fresh H3 instance and real H3Event in
beforeEach, track unhandled errors through ctx.errors, and assert them in
afterEach; update the tests to use these instances and remove event as any casts
while preserving the existing cookie assertions.

Source: Coding guidelines

@pi0
pi0 merged commit 66f47c3 into main Jul 15, 2026
8 of 9 checks passed
@pi0
pi0 deleted the perf/cookie branch July 15, 2026 09:05
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