Skip to content

Commit cea0cc8

Browse files
authored
fix(cookies): work with global Headers (nodejs#1850)
* fix(cookies): work with global Headers * lint: Headers is a global
1 parent 41f8ba0 commit cea0cc8

File tree

6 files changed

+109
-13
lines changed

6 files changed

+109
-13
lines changed

lib/cookies/index.js

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
'use strict'
22

33
const { parseSetCookie } = require('./parse')
4-
const { stringify } = require('./util')
4+
const { stringify, getHeadersList } = require('./util')
55
const { webidl } = require('../fetch/webidl')
66
const { Headers } = require('../fetch/headers')
7-
const { kHeadersList } = require('../core/symbols')
87

98
/**
109
* @typedef {Object} Cookie
@@ -27,9 +26,9 @@ const { kHeadersList } = require('../core/symbols')
2726
function getCookies (headers) {
2827
webidl.argumentLengthCheck(arguments, 1, { header: 'getCookies' })
2928

30-
webidl.brandCheck(headers, Headers)
29+
webidl.brandCheck(headers, Headers, { strict: false })
3130

32-
const cookie = headers[kHeadersList].get('cookie')
31+
const cookie = headers.get('cookie')
3332
const out = {}
3433

3534
if (!cookie) {
@@ -54,7 +53,7 @@ function getCookies (headers) {
5453
function deleteCookie (headers, name, attributes) {
5554
webidl.argumentLengthCheck(arguments, 2, { header: 'deleteCookie' })
5655

57-
webidl.brandCheck(headers, Headers)
56+
webidl.brandCheck(headers, Headers, { strict: false })
5857

5958
name = webidl.converters.DOMString(name)
6059
attributes = webidl.converters.DeleteCookieAttributes(attributes)
@@ -76,9 +75,9 @@ function deleteCookie (headers, name, attributes) {
7675
function getSetCookies (headers) {
7776
webidl.argumentLengthCheck(arguments, 1, { header: 'getSetCookies' })
7877

79-
webidl.brandCheck(headers, Headers)
78+
webidl.brandCheck(headers, Headers, { strict: false })
8079

81-
const cookies = headers[kHeadersList].cookies
80+
const cookies = getHeadersList(headers).cookies
8281

8382
if (!cookies) {
8483
return []
@@ -95,7 +94,7 @@ function getSetCookies (headers) {
9594
function setCookie (headers, cookie) {
9695
webidl.argumentLengthCheck(arguments, 2, { header: 'setCookie' })
9796

98-
webidl.brandCheck(headers, Headers)
97+
webidl.brandCheck(headers, Headers, { strict: false })
9998

10099
cookie = webidl.converters.Cookie(cookie)
101100

lib/cookies/util.js

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
'use strict'
22

3+
const assert = require('assert')
4+
const { kHeadersList } = require('../core/symbols')
5+
36
function isCTLExcludingHtab (value) {
47
if (value.length === 0) {
58
return false
@@ -260,7 +263,29 @@ function stringify (cookie) {
260263
return out.join('; ')
261264
}
262265

266+
let kHeadersListNode
267+
268+
function getHeadersList (headers) {
269+
if (headers[kHeadersList]) {
270+
return headers[kHeadersList]
271+
}
272+
273+
if (!kHeadersListNode) {
274+
kHeadersListNode = Object.getOwnPropertySymbols(headers).find(
275+
(symbol) => symbol.description === 'headers list'
276+
)
277+
278+
assert(kHeadersListNode, 'Headers cannot be parsed')
279+
}
280+
281+
const headersList = headers[kHeadersListNode]
282+
assert(headersList)
283+
284+
return headersList
285+
}
286+
263287
module.exports = {
264288
isCTLExcludingHtab,
265-
stringify
289+
stringify,
290+
getHeadersList
266291
}

lib/fetch/webidl.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ webidl.errors.invalidArgument = function (context) {
3333
}
3434

3535
// https://webidl.spec.whatwg.org/#implements
36-
webidl.brandCheck = function (V, I) {
37-
if (!(V instanceof I)) {
36+
webidl.brandCheck = function (V, I, opts = undefined) {
37+
if (opts?.strict !== false && !(V instanceof I)) {
3838
throw new TypeError('Illegal invocation')
39+
} else {
40+
return V?.[Symbol.toStringTag] === I.prototype[Symbol.toStringTag]
3941
}
4042
}
4143

test/cookie/global-headers.js

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
'use strict'
2+
3+
const { test, skip } = require('tap')
4+
const {
5+
deleteCookie,
6+
getCookies,
7+
getSetCookies,
8+
setCookie
9+
} = require('../..')
10+
const { getHeadersList } = require('../../lib/cookies/util')
11+
12+
/* global Headers */
13+
14+
if (!globalThis.Headers) {
15+
skip('No global Headers to test')
16+
process.exit(0)
17+
}
18+
19+
test('Using global Headers', (t) => {
20+
t.test('deleteCookies', (t) => {
21+
const headers = new Headers()
22+
23+
t.equal(headers.get('set-cookie'), null)
24+
deleteCookie(headers, 'undici')
25+
t.equal(headers.get('set-cookie'), 'undici=; Expires=Thu, 01 Jan 1970 00:00:00 GMT')
26+
27+
t.end()
28+
})
29+
30+
t.test('getCookies', (t) => {
31+
const headers = new Headers({
32+
cookie: 'get=cookies; and=attributes'
33+
})
34+
35+
t.same(getCookies(headers), { get: 'cookies', and: 'attributes' })
36+
t.end()
37+
})
38+
39+
t.test('getSetCookies', (t) => {
40+
const headers = new Headers({
41+
'set-cookie': 'undici=getSetCookies; Secure'
42+
})
43+
44+
const supportsCookies = getHeadersList(headers).cookies
45+
46+
if (!supportsCookies) {
47+
t.same(getSetCookies(headers), [])
48+
} else {
49+
t.same(getSetCookies(headers), [
50+
{
51+
name: 'undici',
52+
value: 'getSetCookies',
53+
secure: true
54+
}
55+
])
56+
}
57+
58+
t.end()
59+
})
60+
61+
t.test('setCookie', (t) => {
62+
const headers = new Headers()
63+
64+
setCookie(headers, { name: 'undici', value: 'setCookie' })
65+
t.equal(headers.get('Set-Cookie'), 'undici=setCookie')
66+
t.end()
67+
})
68+
69+
t.end()
70+
})

types/cookies.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export interface Cookie {
1515
unparsed?: string[]
1616
}
1717

18-
export function deleteCookies (
18+
export function deleteCookie (
1919
headers: Headers,
2020
name: string,
2121
attributes?: { name?: string, domain?: string }

types/webidl.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ export interface Webidl {
162162
* @description Performs a brand-check on {@param V} to ensure it is a
163163
* {@param cls} object.
164164
*/
165-
brandCheck <Interface>(V: unknown, cls: Interface): asserts V is Interface
165+
brandCheck <Interface>(V: unknown, cls: Interface, opts?: { strict?: boolean }): asserts V is Interface
166166

167167
/**
168168
* @see https://webidl.spec.whatwg.org/#es-sequence

0 commit comments

Comments
 (0)