Skip to content

Commit

Permalink
http: speed up checkIsHttpToken
Browse files Browse the repository at this point in the history
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 <jasnell@gmail.com>
Reviewed-By: Brian White <mscdex@mscdex.net>
  • Loading branch information
JacksonTian authored and Myles Borins committed Jun 1, 2016
1 parent e84a29c commit 4c7272a
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 2 deletions.
52 changes: 52 additions & 0 deletions benchmark/http/check_is_http_token.js
Original file line number Diff line number Diff line change
@@ -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 changes: 48 additions & 2 deletions lib/_http_common.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit 4c7272a

Please sign in to comment.