2025-04-02 06:50:39 -04:00

202 lines
4.3 KiB
JavaScript

'use strict';
const { parseSetCookie } = require('./parse');
const { stringify } = require('./util');
const { webidl } = require('../fetch/webidl');
const { Headers } = require('../fetch/headers');
const brandChecks = webidl.brandCheckMultiple(
[Headers, globalThis.Headers].filter(Boolean)
);
/**
* @typedef {Object} Cookie
* @property {string} name
* @property {string} value
* @property {Date|number} [expires]
* @property {number} [maxAge]
* @property {string} [domain]
* @property {string} [path]
* @property {boolean} [secure]
* @property {boolean} [httpOnly]
* @property {'Strict'|'Lax'|'None'} [sameSite]
* @property {string[]} [unparsed]
*/
/**
* @param {Headers} headers
* @returns {Record<string, string>}
*/
function getCookies(headers) {
webidl.argumentLengthCheck(arguments, 1, 'getCookies');
brandChecks(headers);
const cookie = headers.get('cookie');
/** @type {Record<string, string>} */
const out = {};
if (!cookie) {
return out;
}
for (const piece of cookie.split(';')) {
const [name, ...value] = piece.split('=');
out[name.trim()] = value.join('=');
}
return out;
}
/**
* @param {Headers} headers
* @param {string} name
* @param {{ path?: string, domain?: string }|undefined} attributes
* @returns {void}
*/
function deleteCookie(headers, name, attributes) {
brandChecks(headers);
const prefix = 'deleteCookie';
webidl.argumentLengthCheck(arguments, 2, prefix);
name = webidl.converters.DOMString(name, prefix, 'name');
attributes = webidl.converters.DeleteCookieAttributes(attributes);
// Matches behavior of
// https://github.com/denoland/deno_std/blob/63827b16330b82489a04614027c33b7904e08be5/http/cookie.ts#L278
setCookie(headers, {
name,
value: '',
expires: new Date(0),
...attributes,
});
}
/**
* @param {Headers} headers
* @returns {Cookie[]}
*/
function getSetCookies(headers) {
webidl.argumentLengthCheck(arguments, 1, 'getSetCookies');
brandChecks(headers);
const cookies = headers.getSetCookie();
if (!cookies) {
return [];
}
return cookies.map((pair) => parseSetCookie(pair));
}
/**
* Parses a cookie string
* @param {string} cookie
*/
function parseCookie(cookie) {
cookie = webidl.converters.DOMString(cookie);
return parseSetCookie(cookie);
}
/**
* @param {Headers} headers
* @param {Cookie} cookie
* @returns {void}
*/
function setCookie(headers, cookie) {
webidl.argumentLengthCheck(arguments, 2, 'setCookie');
brandChecks(headers);
cookie = webidl.converters.Cookie(cookie);
const str = stringify(cookie);
if (str) {
headers.append('set-cookie', str, true);
}
}
webidl.converters.DeleteCookieAttributes = webidl.dictionaryConverter([
{
converter: webidl.nullableConverter(webidl.converters.DOMString),
key: 'path',
defaultValue: () => null,
},
{
converter: webidl.nullableConverter(webidl.converters.DOMString),
key: 'domain',
defaultValue: () => null,
},
]);
webidl.converters.Cookie = webidl.dictionaryConverter([
{
converter: webidl.converters.DOMString,
key: 'name',
},
{
converter: webidl.converters.DOMString,
key: 'value',
},
{
converter: webidl.nullableConverter((value) => {
if (typeof value === 'number') {
return webidl.converters['unsigned long long'](value);
}
return new Date(value);
}),
key: 'expires',
defaultValue: () => null,
},
{
converter: webidl.nullableConverter(webidl.converters['long long']),
key: 'maxAge',
defaultValue: () => null,
},
{
converter: webidl.nullableConverter(webidl.converters.DOMString),
key: 'domain',
defaultValue: () => null,
},
{
converter: webidl.nullableConverter(webidl.converters.DOMString),
key: 'path',
defaultValue: () => null,
},
{
converter: webidl.nullableConverter(webidl.converters.boolean),
key: 'secure',
defaultValue: () => null,
},
{
converter: webidl.nullableConverter(webidl.converters.boolean),
key: 'httpOnly',
defaultValue: () => null,
},
{
converter: webidl.converters.USVString,
key: 'sameSite',
allowedValues: ['Strict', 'Lax', 'None'],
},
{
converter: webidl.sequenceConverter(webidl.converters.DOMString),
key: 'unparsed',
defaultValue: () => new Array(0),
},
]);
module.exports = {
getCookies,
deleteCookie,
getSetCookies,
setCookie,
parseCookie,
};