Browse Source

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: https://github.com/nodejs/node/pull/4790
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Brian White <mscdex@mscdex.net>
process-exit-stdio-flushing
Jackson Tian 9 years ago
committed by James M Snell
parent
commit
089c6a4fba
  1. 52
      benchmark/http/check_is_http_token.js
  2. 50
      lib/_http_common.js

52
benchmark/http/check_is_http_token.js

@ -0,0 +1,52 @@
'use strict';
const common = require('../common.js');
const _checkIsHttpToken = require('_http_common')._checkIsHttpToken;
const bench = common.createBenchmark(main, {
key: [
'TCN',
'ETag',
'date',
'Vary',
'server',
'Server',
'status',
'version',
'Expires',
'alt-svc',
'location',
'Connection',
'Keep-Alive',
'content-type',
'Content-Type',
'Cache-Control',
'Last-Modified',
'Accept-Ranges',
'content-length',
'x-frame-options',
'x-xss-protection',
'Content-Encoding',
'Content-Location',
'Transfer-Encoding',
'alternate-protocol',
':', // invalid input
'@@',
'中文呢', // unicode
'((((())))', // invalid
':alternate-protocol', // fast bailout
'alternate-protocol:' // slow bailout
],
n: [1e6],
});
function main(conf) {
var n = +conf.n;
var key = conf.key;
bench.start();
for (var i = 0; i < n; i++) {
_checkIsHttpToken(key);
}
bench.end(n);
}

50
lib/_http_common.js

@ -225,10 +225,56 @@ exports.httpSocketSetup = httpSocketSetup;
/**
* Verifies that the given val is a valid HTTP token
* per the rules defined in RFC 7230
* See https://tools.ietf.org/html/rfc7230#section-3.2.6
*
* This implementation of checkIsHttpToken() loops over the string instead of
* using a regular expression since the former is up to 180% faster with v8 4.9
* depending on the string length (the shorter the string, the larger the
* performance difference)
**/
const token = /^[a-zA-Z0-9_!#$%&'*+.^`|~-]+$/;
function checkIsHttpToken(val) {
return typeof val === 'string' && token.test(val);
if (typeof val !== 'string' || val.length === 0)
return false;
for (var i = 0, len = val.length; i < len; i++) {
var ch = val.charCodeAt(i);
if (ch >= 65 && ch <= 90) // A-Z
continue;
if (ch >= 97 && ch <= 122) // a-z
continue;
// ^ => 94
// _ => 95
// ` => 96
// | => 124
// ~ => 126
if (ch === 94 || ch === 95 || ch === 96 || ch === 124 || ch === 126)
continue;
if (ch >= 48 && ch <= 57) // 0-9
continue;
// ! => 33
// # => 35
// $ => 36
// % => 37
// & => 38
// ' => 39
// * => 42
// + => 43
// - => 45
// . => 46
if (ch >= 33 && ch <= 46) {
if (ch === 34 || ch === 40 || ch === 41 || ch === 44)
return false;
continue;
}
return false;
}
return true;
}
exports._checkIsHttpToken = checkIsHttpToken;

Loading…
Cancel
Save