185 lines
4.2 KiB
JavaScript
185 lines
4.2 KiB
JavaScript
|
'use strict'
|
||
|
|
||
|
const { parseSetCookie } = require('./parse')
|
||
|
const { stringify, getHeadersList } = require('./util')
|
||
|
const { webidl } = require('../fetch/webidl')
|
||
|
const { Headers } = require('../fetch/headers')
|
||
|
|
||
|
/**
|
||
|
* @typedef {Object} Cookie
|
||
|
* @property {string} name
|
||
|
* @property {string} value
|
||
|
* @property {Date|number|undefined} expires
|
||
|
* @property {number|undefined} maxAge
|
||
|
* @property {string|undefined} domain
|
||
|
* @property {string|undefined} path
|
||
|
* @property {boolean|undefined} secure
|
||
|
* @property {boolean|undefined} httpOnly
|
||
|
* @property {'Strict'|'Lax'|'None'} sameSite
|
||
|
* @property {string[]} unparsed
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @param {Headers} headers
|
||
|
* @returns {Record<string, string>}
|
||
|
*/
|
||
|
function getCookies (headers) {
|
||
|
webidl.argumentLengthCheck(arguments, 1, { header: 'getCookies' })
|
||
|
|
||
|
webidl.brandCheck(headers, Headers, { strict: false })
|
||
|
|
||
|
const cookie = headers.get('cookie')
|
||
|
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) {
|
||
|
webidl.argumentLengthCheck(arguments, 2, { header: 'deleteCookie' })
|
||
|
|
||
|
webidl.brandCheck(headers, Headers, { strict: false })
|
||
|
|
||
|
name = webidl.converters.DOMString(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, { header: 'getSetCookies' })
|
||
|
|
||
|
webidl.brandCheck(headers, Headers, { strict: false })
|
||
|
|
||
|
const cookies = getHeadersList(headers).cookies
|
||
|
|
||
|
if (!cookies) {
|
||
|
return []
|
||
|
}
|
||
|
|
||
|
// In older versions of undici, cookies is a list of name:value.
|
||
|
return cookies.map((pair) => parseSetCookie(Array.isArray(pair) ? pair[1] : pair))
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {Headers} headers
|
||
|
* @param {Cookie} cookie
|
||
|
* @returns {void}
|
||
|
*/
|
||
|
function setCookie (headers, cookie) {
|
||
|
webidl.argumentLengthCheck(arguments, 2, { header: 'setCookie' })
|
||
|
|
||
|
webidl.brandCheck(headers, Headers, { strict: false })
|
||
|
|
||
|
cookie = webidl.converters.Cookie(cookie)
|
||
|
|
||
|
const str = stringify(cookie)
|
||
|
|
||
|
if (str) {
|
||
|
headers.append('Set-Cookie', stringify(cookie))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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: []
|
||
|
}
|
||
|
])
|
||
|
|
||
|
module.exports = {
|
||
|
getCookies,
|
||
|
deleteCookie,
|
||
|
getSetCookies,
|
||
|
setCookie
|
||
|
}
|