@fastify/cookie
Advanced tools
Comparing version 9.2.0 to 9.3.0
@@ -32,18 +32,2 @@ /*! | ||
/** | ||
* Module exports. | ||
* @public | ||
*/ | ||
exports.parse = parse | ||
exports.serialize = serialize | ||
/** | ||
* Module variables. | ||
* @private | ||
*/ | ||
const decode = decodeURIComponent | ||
const encode = encodeURIComponent | ||
/** | ||
* RegExp to match field-content in RFC 7230 sec 3.2 | ||
@@ -65,3 +49,3 @@ * | ||
* @param {string} str | ||
* @param {object} [options] | ||
* @param {object} [opt] | ||
* @return {object} | ||
@@ -71,3 +55,3 @@ * @public | ||
function parse (str, options) { | ||
function parse (str, opt) { | ||
if (typeof str !== 'string') { | ||
@@ -77,19 +61,17 @@ throw new TypeError('argument str must be a string') | ||
const dec = opt?.decode || decodeURIComponent | ||
const result = {} | ||
const dec = (options && options.decode) || decode | ||
const strLen = str.length | ||
let pos = 0 | ||
let terminatorPos = 0 | ||
let eqIdx = 0 | ||
while (true) { | ||
if (terminatorPos === str.length) { | ||
break | ||
} | ||
if (terminatorPos === strLen) break | ||
terminatorPos = str.indexOf(';', pos) | ||
terminatorPos = (terminatorPos === -1) ? str.length : terminatorPos | ||
eqIdx = str.indexOf('=', pos) | ||
if (terminatorPos === -1) terminatorPos = strLen // This is the last pair | ||
// skip things that don't look like key=value | ||
if (eqIdx === -1 || eqIdx > terminatorPos) { | ||
let eqIdx = str.indexOf('=', pos) | ||
if (eqIdx === -1) break // No key-value pairs left | ||
if (eqIdx > terminatorPos) { | ||
// Malformed key-value pair | ||
pos = terminatorPos + 1 | ||
@@ -100,15 +82,15 @@ continue | ||
const key = str.substring(pos, eqIdx++).trim() | ||
// only assign once | ||
if (result[key] === undefined) { | ||
const val = (str.charCodeAt(eqIdx) === 0x22) | ||
const val = str.charCodeAt(eqIdx) === 0x22 | ||
? str.substring(eqIdx + 1, terminatorPos - 1).trim() | ||
: str.substring(eqIdx, terminatorPos).trim() | ||
result[key] = (dec !== decode || val.indexOf('%') !== -1) | ||
result[key] = !(dec === decodeURIComponent && val.indexOf('%') === -1) | ||
? tryDecode(val, dec) | ||
: val | ||
} | ||
pos = terminatorPos + 1 | ||
} | ||
return result | ||
@@ -128,3 +110,3 @@ } | ||
* @param {string} val | ||
* @param {object} [options] | ||
* @param {object} [opt] | ||
* @return {string} | ||
@@ -134,5 +116,4 @@ * @public | ||
function serialize (name, val, options) { | ||
const opt = options || {} | ||
const enc = opt.encode || encode | ||
function serialize (name, val, opt) { | ||
const enc = opt?.encode || encodeURIComponent | ||
if (typeof enc !== 'function') { | ||
@@ -142,3 +123,3 @@ throw new TypeError('option encode is invalid') | ||
if (!fieldContentRegExp.test(name)) { | ||
if (name && !fieldContentRegExp.test(name)) { | ||
throw new TypeError('argument name is invalid') | ||
@@ -153,9 +134,13 @@ } | ||
let str = name + '=' + value | ||
if (opt == null) return str | ||
if (opt.maxAge != null) { | ||
const maxAge = opt.maxAge - 0 | ||
if (isNaN(maxAge) || !isFinite(maxAge)) { | ||
const maxAge = +opt.maxAge | ||
if (!isFinite(maxAge)) { | ||
throw new TypeError('option maxAge is invalid') | ||
} | ||
str += '; Max-Age=' + Math.floor(maxAge) | ||
str += '; Max-Age=' + Math.trunc(maxAge) | ||
} | ||
@@ -205,2 +190,3 @@ | ||
: opt.sameSite | ||
switch (sameSite) { | ||
@@ -232,11 +218,21 @@ case true: | ||
* @param {function} decode | ||
* @returns {string} | ||
* @private | ||
*/ | ||
function tryDecode (str, decode) { | ||
try { | ||
return decode(str) | ||
} catch (e) { | ||
} catch { | ||
return str | ||
} | ||
} | ||
/** | ||
* Module exports. | ||
* @public | ||
*/ | ||
module.exports = { | ||
parse, | ||
serialize | ||
} |
{ | ||
"name": "@fastify/cookie", | ||
"version": "9.2.0", | ||
"version": "9.3.0", | ||
"description": "Plugin for fastify to add support for cookies", | ||
@@ -51,3 +51,3 @@ "main": "plugin.js", | ||
"tap": "^16.0.0", | ||
"tsd": "^0.29.0" | ||
"tsd": "^0.30.0" | ||
}, | ||
@@ -54,0 +54,0 @@ "dependencies": { |
@@ -73,28 +73,27 @@ 'use strict' | ||
function setCookies (reply) { | ||
let setCookie = reply.getHeader('Set-Cookie') | ||
const setCookieIsUndefined = setCookie === undefined | ||
const setCookieHeaderValue = reply.getHeader('Set-Cookie') | ||
let cookieValue | ||
/* istanbul ignore else */ | ||
if (setCookieIsUndefined) { | ||
if (setCookieHeaderValue === undefined) { | ||
if (reply[kReplySetCookies].size === 1) { | ||
for (const c of reply[kReplySetCookies].values()) { | ||
reply.header('Set-Cookie', cookie.serialize(c.name, c.value, c.opts)) | ||
} | ||
// Fast path for single cookie | ||
const c = reply[kReplySetCookies].values().next().value | ||
reply.header('Set-Cookie', cookie.serialize(c.name, c.value, c.opts)) | ||
reply[kReplySetCookies].clear() | ||
return | ||
} | ||
setCookie = [] | ||
} else if (typeof setCookie === 'string') { | ||
setCookie = [setCookie] | ||
cookieValue = [] | ||
} else if (typeof setCookieHeaderValue === 'string') { | ||
cookieValue = [setCookieHeaderValue] | ||
} else { | ||
cookieValue = setCookieHeaderValue | ||
} | ||
for (const c of reply[kReplySetCookies].values()) { | ||
setCookie.push(cookie.serialize(c.name, c.value, c.opts)) | ||
cookieValue.push(cookie.serialize(c.name, c.value, c.opts)) | ||
} | ||
if (!setCookieIsUndefined) reply.removeHeader('Set-Cookie') | ||
reply.header('Set-Cookie', setCookie) | ||
reply.removeHeader('Set-Cookie') | ||
reply.header('Set-Cookie', cookieValue) | ||
reply[kReplySetCookies].clear() | ||
@@ -218,2 +217,5 @@ } | ||
module.exports.serialize = cookie.serialize | ||
module.exports.parse = cookie.parse | ||
module.exports.signerFactory = Signer | ||
@@ -220,0 +222,0 @@ module.exports.Signer = Signer |
@@ -7,3 +7,3 @@ # @fastify/cookie | ||
A plugin for [Fastify](http://fastify.io/) that adds support for reading and | ||
A plugin for [Fastify](http://fastify.dev/) that adds support for reading and | ||
setting cookies. | ||
@@ -15,2 +15,4 @@ | ||
It is also possible to [import the low-level cookie parsing and serialization functions](#importing-serialize-and-parse). | ||
`@fastify/cookie` [v2.x](https://github.com/fastify/fastify-cookie/tree/v2.x) | ||
@@ -75,2 +77,19 @@ supports both Fastify@1 and Fastify@2. | ||
## Importing `serialize` and `parse` | ||
```js | ||
const { serialize, parse } = require('@fastify/cookie') | ||
const fastify = require('fastify')() | ||
fastify.get('/', (req, reply) => { | ||
const cookie = serialize('lang', 'en', { | ||
maxAge: 60_000, | ||
}) | ||
reply.header('Set-Cookie', cookie) | ||
reply.send('Language set!') | ||
}) | ||
``` | ||
## Options | ||
@@ -77,0 +96,0 @@ |
@@ -6,3 +6,3 @@ 'use strict' | ||
const cookie = require('../cookie') | ||
const cookie = require('..') | ||
@@ -9,0 +9,0 @@ test('parse: argument validation', (t) => { |
@@ -135,2 +135,35 @@ 'use strict' | ||
test('should set multiple cookies (an array already exists)', (t) => { | ||
t.plan(10) | ||
const fastify = Fastify() | ||
fastify.register(plugin) | ||
fastify.get('/test1', (req, reply) => { | ||
reply | ||
.header('Set-Cookie', ['bar=bar']) | ||
.setCookie('foo', 'foo', { path: '/' }) | ||
.setCookie('foo', 'foo', { path: '/path' }) | ||
.send({ hello: 'world' }) | ||
}) | ||
fastify.inject({ | ||
method: 'GET', | ||
url: '/test1' | ||
}, (err, res) => { | ||
t.error(err) | ||
t.equal(res.statusCode, 200) | ||
t.same(JSON.parse(res.body), { hello: 'world' }) | ||
const cookies = res.cookies | ||
t.equal(cookies.length, 3) | ||
t.equal(cookies[0].name, 'bar') | ||
t.equal(cookies[0].value, 'bar') | ||
t.equal(cookies[0].path, undefined) | ||
t.equal(cookies[1].name, 'foo') | ||
t.equal(cookies[1].value, 'foo') | ||
t.equal(cookies[2].path, '/path') | ||
}) | ||
}) | ||
test('cookies get set correctly with millisecond dates', (t) => { | ||
@@ -137,0 +170,0 @@ t.plan(8) |
@@ -68,7 +68,3 @@ /// <reference types='node' /> | ||
*/ | ||
setCookie( | ||
name: string, | ||
value: string, | ||
options?: fastifyCookie.CookieSerializeOptions | ||
): this; | ||
setCookie: setCookieWrapper; | ||
@@ -143,2 +139,6 @@ /** | ||
export interface ParseOptions { | ||
decode?: (encodedURIComponent: string) => string; | ||
} | ||
type HookType = 'onRequest' | 'preParsing' | 'preValidation' | 'preHandler' | 'preSerialization'; | ||
@@ -167,2 +167,4 @@ | ||
export interface FastifyCookie extends FastifyCookiePlugin { | ||
parse: (cookieHeader: string, opts?: ParseOptions) => { [key: string]: string }; | ||
serialize: (name: string, value: string, opts?: SerializeOptions) => string; | ||
signerFactory: SignerFactory; | ||
@@ -169,0 +171,0 @@ Signer: Signer; |
@@ -235,1 +235,4 @@ import cookie from '..'; | ||
expectError(appWithHook.register(cookie, { hook: 'false' })); | ||
expectType<(cookieHeader: string, opts?: fastifyCookieStar.ParseOptions) => { [key: string]: string }>(fastifyCookieDefault.parse); | ||
expectType<(name: string, value: string, opts?: fastifyCookieStar.SerializeOptions) => string>(fastifyCookieDefault.serialize); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
92202
2308
364
1