Skip to content

fix: forward custom encode option to cookie serializer - #377

Open
ezefernandezyf wants to merge 1 commit into
fastify:mainfrom
ezefernandezyf:fix/set-cookie-encode-forwarding
Open

ezefernandezyf wants to merge 1 commit into
fastify:mainfrom
ezefernandezyf:fix/set-cookie-encode-forwarding

Conversation

@ezefernandezyf

@ezefernandezyf ezefernandezyf commented Sep 24, 2026 •

Copy link
Copy Markdown

What this fixes

Fixes #376

reply.setCookie(), fastify.serializeCookie() and the exported serialize() stopped
honoring the documented encode option after the cookie v2.x migration.

reply.setCookie('test', 'a=%2F&b=c', { encode: String })
// 11.0.2:  test=a=%2F&b=c; SameSite=Lax
// 11.1.2:  test=a%3D%252F%26b%3Dc; SameSite=Lax

The caller's encoder is ignored and the default encodeURIComponent is used instead, so an
already escaped value is escaped a second time (%2F becomes %252F). The header also grows
(4091 to 4103 bytes in the report), which can push a cookie past the 4096 byte limit browsers
commonly enforce, causing the client to drop the cookie entirely.

Root cause

cookie v2 split its stringify API into two arguments:

stringifySetCookie(cookie: SetCookie, options?: StringifyOptions)

encode belongs to StringifyOptions, while the cookie attributes (name, value, sameSite,
...) stay in the first argument. Since the migration (#361) the plugin merged every option into the
first argument, so encode was silently ignored: JavaScript does not complain about a key the
called function never reads.

What to review first

  1. index.js, serialize(): encode is destructured out of the attributes and passed as the
    second argument. That is the whole fix.
  2. options || {} is load bearing, not defensive noise. fastify.serializeCookie(name, value) is
    a public call path with an optional options object and types/index.tst.ts exercises it with two
    arguments. The previous code tolerated undefined because Object.assign({ name, value }, undefined) is legal, and a bare destructuring would throw a TypeError there. There is a test
    for this path.
  3. The two encode tests, which fail against main and pass with the fix.

Verification

  • npm test green: 56 unit tests, c8 --100 coverage intact, 46 tstyche assertions.
  • npm run lint clean.
  • The regression tests were run against a pristine worktree at the pre-fix commit and fail there.
  • When no encode is supplied the output is byte identical to before, because cookie v2 resolves
    the encoder as encode || defaultEncode.

Out of scope

  • Other cookie v2 API differences.
  • Changes to the published types: encode was already declared in SerializeOptions.

Fixes #376

cookie v2 split the stringify API into two arguments:

    stringifySetCookie(cookie: SetCookie, options?: StringifyOptions)

`encode` belongs to `StringifyOptions`, while the cookie attributes stay in
the first argument. Since the cookie v2.x migration (fastify#361) every option was
merged into the first argument, so a custom `encode` was silently dropped and
the default encoder was used instead, double encoding the value: `%2F`
became `%252F`.

Split `encode` out of the attributes and pass it as the second argument.
`options || {}` is required because `fastify.serializeCookie(name, value)` is
a public call path with an optional options object, and a bare destructuring
would throw a TypeError there.

Refs: fastify#376
@ezefernandezyf

Copy link
Copy Markdown
Author

Found #374 after opening this one, which covers the same fix. I am leaving this open in case the maintainers prefer the stricter shape: here only encode is split out of the attributes, rather than forwarding the whole options object as the stringify options.

It also adds coverage for the other two paths through the same helper: fastify.serializeCookie(name, value) with no options argument, and the serialize module export.

This closes #376, which was filed after #374 and is not referenced there.

Happy to close this if #374 is the preferred path.

This branch has not been deployed

No deployments
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.

reply.setCookie() does not forward the custom encode option to cookie@2 in @fastify/cookie 11.1.2

1 participant