Skip to content

Commit 4106830

Browse files
authored
cookies: improve validateCookieName (nodejs#2884)
1 parent 6cd5f09 commit 4106830

File tree

3 files changed

+164
-20
lines changed

3 files changed

+164
-20
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { bench, group, run } from 'mitata'
2+
import { validateCookieName } from '../../lib/web/cookies/util.js'
3+
4+
const valid = 'Cat'
5+
6+
group('validateCookieName', () => {
7+
bench(`valid: ${valid}`, () => {
8+
return validateCookieName(valid)
9+
})
10+
})
11+
12+
await run()

lib/web/cookies/util.js

+22-20
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,29 @@ function isCTLExcludingHtab (value) {
3232
* @param {string} name
3333
*/
3434
function validateCookieName (name) {
35-
for (const char of name) {
36-
const code = char.charCodeAt(0)
35+
for (let i = 0; i < name.length; ++i) {
36+
const code = name.charCodeAt(i)
3737

3838
if (
39-
(code <= 0x20 || code > 0x7F) ||
40-
char === '(' ||
41-
char === ')' ||
42-
char === '>' ||
43-
char === '<' ||
44-
char === '@' ||
45-
char === ',' ||
46-
char === ';' ||
47-
char === ':' ||
48-
char === '\\' ||
49-
char === '"' ||
50-
char === '/' ||
51-
char === '[' ||
52-
char === ']' ||
53-
char === '?' ||
54-
char === '=' ||
55-
char === '{' ||
56-
char === '}'
39+
code < 0x21 || // exclude CTLs (0-31), SP and HT
40+
code > 0x7E || // exclude non-ascii and DEL
41+
code === 0x22 || // "
42+
code === 0x28 || // (
43+
code === 0x29 || // )
44+
code === 0x3C || // <
45+
code === 0x3E || // >
46+
code === 0x40 || // @
47+
code === 0x2C || // ,
48+
code === 0x3B || // ;
49+
code === 0x3A || // :
50+
code === 0x5C || // \
51+
code === 0x2F || // /
52+
code === 0x5B || // [
53+
code === 0x5D || // ]
54+
code === 0x3F || // ?
55+
code === 0x3D || // =
56+
code === 0x7B || // {
57+
code === 0x7D // }
5758
) {
5859
throw new Error('Invalid cookie name')
5960
}
@@ -297,6 +298,7 @@ function getHeadersList (headers) {
297298

298299
module.exports = {
299300
isCTLExcludingHtab,
301+
validateCookieName,
300302
validateCookiePath,
301303
validateCookieValue,
302304
toIMFDate,

test/cookie/validate-cookie-name.js

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
'use strict'
2+
3+
const { test, describe } = require('node:test')
4+
const { throws, strictEqual } = require('node:assert')
5+
6+
const {
7+
validateCookieName
8+
} = require('../../lib/web/cookies/util')
9+
10+
describe('validateCookieName', () => {
11+
test('should throw for CTLs', () => {
12+
throws(() => validateCookieName('\x00'), new Error('Invalid cookie name'))
13+
throws(() => validateCookieName('\x01'), new Error('Invalid cookie name'))
14+
throws(() => validateCookieName('\x02'), new Error('Invalid cookie name'))
15+
throws(() => validateCookieName('\x03'), new Error('Invalid cookie name'))
16+
throws(() => validateCookieName('\x04'), new Error('Invalid cookie name'))
17+
throws(() => validateCookieName('\x05'), new Error('Invalid cookie name'))
18+
throws(() => validateCookieName('\x06'), new Error('Invalid cookie name'))
19+
throws(() => validateCookieName('\x07'), new Error('Invalid cookie name'))
20+
throws(() => validateCookieName('\x08'), new Error('Invalid cookie name'))
21+
throws(() => validateCookieName('\x09'), new Error('Invalid cookie name'))
22+
throws(() => validateCookieName('\x0A'), new Error('Invalid cookie name'))
23+
throws(() => validateCookieName('\x0B'), new Error('Invalid cookie name'))
24+
throws(() => validateCookieName('\x0C'), new Error('Invalid cookie name'))
25+
throws(() => validateCookieName('\x0D'), new Error('Invalid cookie name'))
26+
throws(() => validateCookieName('\x0E'), new Error('Invalid cookie name'))
27+
throws(() => validateCookieName('\x0F'), new Error('Invalid cookie name'))
28+
throws(() => validateCookieName('\x10'), new Error('Invalid cookie name'))
29+
throws(() => validateCookieName('\x11'), new Error('Invalid cookie name'))
30+
throws(() => validateCookieName('\x12'), new Error('Invalid cookie name'))
31+
throws(() => validateCookieName('\x13'), new Error('Invalid cookie name'))
32+
throws(() => validateCookieName('\x14'), new Error('Invalid cookie name'))
33+
throws(() => validateCookieName('\x15'), new Error('Invalid cookie name'))
34+
throws(() => validateCookieName('\x16'), new Error('Invalid cookie name'))
35+
throws(() => validateCookieName('\x17'), new Error('Invalid cookie name'))
36+
throws(() => validateCookieName('\x18'), new Error('Invalid cookie name'))
37+
throws(() => validateCookieName('\x19'), new Error('Invalid cookie name'))
38+
throws(() => validateCookieName('\x1A'), new Error('Invalid cookie name'))
39+
throws(() => validateCookieName('\x1B'), new Error('Invalid cookie name'))
40+
throws(() => validateCookieName('\x1C'), new Error('Invalid cookie name'))
41+
throws(() => validateCookieName('\x1D'), new Error('Invalid cookie name'))
42+
throws(() => validateCookieName('\x1E'), new Error('Invalid cookie name'))
43+
throws(() => validateCookieName('\x1F'), new Error('Invalid cookie name'))
44+
throws(() => validateCookieName('\x7F'), new Error('Invalid cookie name'))
45+
})
46+
47+
test('should throw for " " character', () => {
48+
throws(() => validateCookieName(' '), new Error('Invalid cookie name'))
49+
})
50+
51+
test('should throw for Horizontal Tab character', () => {
52+
throws(() => validateCookieName('\t'), new Error('Invalid cookie name'))
53+
})
54+
55+
test('should throw for ; character', () => {
56+
throws(() => validateCookieName(';'), new Error('Invalid cookie name'))
57+
})
58+
59+
test('should throw for " character', () => {
60+
throws(() => validateCookieName('"'), new Error('Invalid cookie name'))
61+
})
62+
63+
test('should throw for , character', () => {
64+
throws(() => validateCookieName(','), new Error('Invalid cookie name'))
65+
})
66+
67+
test('should throw for \\ character', () => {
68+
throws(() => validateCookieName('\\'), new Error('Invalid cookie name'))
69+
})
70+
71+
test('should throw for ( character', () => {
72+
throws(() => validateCookieName('('), new Error('Invalid cookie name'))
73+
})
74+
75+
test('should throw for ) character', () => {
76+
throws(() => validateCookieName(')'), new Error('Invalid cookie name'))
77+
})
78+
79+
test('should throw for < character', () => {
80+
throws(() => validateCookieName('<'), new Error('Invalid cookie name'))
81+
})
82+
83+
test('should throw for > character', () => {
84+
throws(() => validateCookieName('>'), new Error('Invalid cookie name'))
85+
})
86+
87+
test('should throw for @ character', () => {
88+
throws(() => validateCookieName('@'), new Error('Invalid cookie name'))
89+
})
90+
91+
test('should throw for : character', () => {
92+
throws(() => validateCookieName(':'), new Error('Invalid cookie name'))
93+
})
94+
95+
test('should throw for / character', () => {
96+
throws(() => validateCookieName('/'), new Error('Invalid cookie name'))
97+
})
98+
99+
test('should throw for [ character', () => {
100+
throws(() => validateCookieName('['), new Error('Invalid cookie name'))
101+
})
102+
103+
test('should throw for ] character', () => {
104+
throws(() => validateCookieName(']'), new Error('Invalid cookie name'))
105+
})
106+
107+
test('should throw for ? character', () => {
108+
throws(() => validateCookieName('?'), new Error('Invalid cookie name'))
109+
})
110+
111+
test('should throw for = character', () => {
112+
throws(() => validateCookieName('='), new Error('Invalid cookie name'))
113+
})
114+
115+
test('should throw for { character', () => {
116+
throws(() => validateCookieName('{'), new Error('Invalid cookie name'))
117+
})
118+
119+
test('should throw for } character', () => {
120+
throws(() => validateCookieName('}'), new Error('Invalid cookie name'))
121+
})
122+
123+
test('should pass for a printable character', t => {
124+
strictEqual(validateCookieName('A'), undefined)
125+
strictEqual(validateCookieName('Z'), undefined)
126+
strictEqual(validateCookieName('a'), undefined)
127+
strictEqual(validateCookieName('z'), undefined)
128+
strictEqual(validateCookieName('!'), undefined)
129+
})
130+
})

0 commit comments

Comments
 (0)