Skip to content

Commit c8c6bfa

Browse files
authored
http: optimize checkIsHttpToken for short strings
Use lookup table instead of regex for strings shorter than 10 characters to improve performance for common short header names while maintaining compatibility. PR-URL: #59832 Reviewed-By: Ethan Arrowood <[email protected]> Reviewed-By: Tim Perry <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]>
1 parent c85460b commit c8c6bfa

File tree

1 file changed

+37
-1
lines changed

1 file changed

+37
-1
lines changed

lib/_http_common.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
const {
2525
MathMin,
2626
Symbol,
27+
Uint8Array,
2728
} = primordials;
2829
const { setImmediate } = require('timers');
2930

@@ -205,7 +206,30 @@ function freeParser(parser, req, socket) {
205206
}
206207
}
207208

209+
// Character code ranges for valid HTTP tokens
210+
// Valid chars: ^_`a-zA-Z-0-9!#$%&'*+.|~
211+
// Based on RFC 7230 Section 3.2.6 token definition
212+
// See https://tools.ietf.org/html/rfc7230#section-3.2.6
208213
const tokenRegExp = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/;
214+
const validTokenChars = new Uint8Array([
215+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15
216+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31
217+
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32-47 (!"#$%&'()*+,-./)
218+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48-63 (0-9:;<=>?)
219+
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64-79 (@A-O)
220+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80-95 (P-Z[\]^_)
221+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96-111 (`a-o)
222+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, // 112-127 (p-z{|}~)
223+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128-143
224+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 144-159
225+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160-175
226+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 176-191
227+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192-207
228+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 208-223
229+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 224-239
230+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240-255
231+
]);
232+
209233
/**
210234
* Verifies that the given val is a valid HTTP token
211235
* per the rules defined in RFC 7230
@@ -214,7 +238,19 @@ const tokenRegExp = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/;
214238
* @returns {boolean}
215239
*/
216240
function checkIsHttpToken(val) {
217-
return tokenRegExp.test(val);
241+
if (val.length >= 10) {
242+
return tokenRegExp.test(val);
243+
}
244+
245+
if (val.length === 0) return false;
246+
247+
// Use lookup table for short strings, regex for longer ones
248+
for (let i = 0; i < val.length; i++) {
249+
if (!validTokenChars[val.charCodeAt(i)]) {
250+
return false;
251+
}
252+
}
253+
return true;
218254
}
219255

220256
const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;

0 commit comments

Comments
 (0)