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: nodejs#4790
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Brian White <[email protected]>
  • Loading branch information
JacksonTian authored and jasnell committed Mar 27, 2016
1 parent 293fd04 commit 089c6a4
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 089c6a4

Please sign in to comment.