Skip to content

Commit c98aaf5

Browse files
JacksonTianMyles Borins
authored and
Myles Borins
committed
http: speed up checkIsHttpToken
The Regex implementation is not faster than ascii code compare. the field name is shorter, the speed is faster. benchmark result here: https://bitbucket.org/snippets/JacksonTian/Rnbad/benchmark-result PR-URL: #4790 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Brian White <[email protected]>
1 parent 4c1eb5b commit c98aaf5

File tree

2 files changed

+100
-2
lines changed

2 files changed

+100
-2
lines changed

benchmark/http/check_is_http_token.js

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const _checkIsHttpToken = require('_http_common')._checkIsHttpToken;
5+
6+
const bench = common.createBenchmark(main, {
7+
key: [
8+
'TCN',
9+
'ETag',
10+
'date',
11+
'Vary',
12+
'server',
13+
'Server',
14+
'status',
15+
'version',
16+
'Expires',
17+
'alt-svc',
18+
'location',
19+
'Connection',
20+
'Keep-Alive',
21+
'content-type',
22+
'Content-Type',
23+
'Cache-Control',
24+
'Last-Modified',
25+
'Accept-Ranges',
26+
'content-length',
27+
'x-frame-options',
28+
'x-xss-protection',
29+
'Content-Encoding',
30+
'Content-Location',
31+
'Transfer-Encoding',
32+
'alternate-protocol',
33+
':', // invalid input
34+
'@@',
35+
'中文呢', // unicode
36+
'((((())))', // invalid
37+
':alternate-protocol', // fast bailout
38+
'alternate-protocol:' // slow bailout
39+
],
40+
n: [1e6],
41+
});
42+
43+
function main(conf) {
44+
var n = +conf.n;
45+
var key = conf.key;
46+
47+
bench.start();
48+
for (var i = 0; i < n; i++) {
49+
_checkIsHttpToken(key);
50+
}
51+
bench.end(n);
52+
}

lib/_http_common.js

+48-2
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,56 @@ exports.httpSocketSetup = httpSocketSetup;
225225
/**
226226
* Verifies that the given val is a valid HTTP token
227227
* per the rules defined in RFC 7230
228+
* See https://tools.ietf.org/html/rfc7230#section-3.2.6
229+
*
230+
* This implementation of checkIsHttpToken() loops over the string instead of
231+
* using a regular expression since the former is up to 180% faster with v8 4.9
232+
* depending on the string length (the shorter the string, the larger the
233+
* performance difference)
228234
**/
229-
const token = /^[a-zA-Z0-9_!#$%&'*+.^`|~-]+$/;
230235
function checkIsHttpToken(val) {
231-
return typeof val === 'string' && token.test(val);
236+
if (typeof val !== 'string' || val.length === 0)
237+
return false;
238+
239+
for (var i = 0, len = val.length; i < len; i++) {
240+
var ch = val.charCodeAt(i);
241+
242+
if (ch >= 65 && ch <= 90) // A-Z
243+
continue;
244+
245+
if (ch >= 97 && ch <= 122) // a-z
246+
continue;
247+
248+
// ^ => 94
249+
// _ => 95
250+
// ` => 96
251+
// | => 124
252+
// ~ => 126
253+
if (ch === 94 || ch === 95 || ch === 96 || ch === 124 || ch === 126)
254+
continue;
255+
256+
if (ch >= 48 && ch <= 57) // 0-9
257+
continue;
258+
259+
// ! => 33
260+
// # => 35
261+
// $ => 36
262+
// % => 37
263+
// & => 38
264+
// ' => 39
265+
// * => 42
266+
// + => 43
267+
// - => 45
268+
// . => 46
269+
if (ch >= 33 && ch <= 46) {
270+
if (ch === 34 || ch === 40 || ch === 41 || ch === 44)
271+
return false;
272+
continue;
273+
}
274+
275+
return false;
276+
}
277+
return true;
232278
}
233279
exports._checkIsHttpToken = checkIsHttpToken;
234280

0 commit comments

Comments
 (0)