Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http: simplify checkInvalidHeaderChar #18381

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 52 additions & 29 deletions benchmark/http/check_invalid_header_char.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,66 @@
const common = require('../common.js');
const _checkInvalidHeaderChar = require('_http_common')._checkInvalidHeaderChar;

// Put it here so the benchmark result lines will not be super long.
const LONG_AND_INVALID = 'Here is a value that is really a folded header ' +
'value\r\n this should be supported, but it is not currently';
const groupedInputs = {
// Representative set of inputs from an AcmeAir benchmark run:
// all valid strings, average length 14.4, stdev 13.0
group_acmeair: [
'W/"2-d4cbb29"', 'OK', 'Express', 'X-HTTP-Method-Override', 'Express',
'application/json', 'application/json; charset=utf-8', '206', 'OK',
'sessionid=; Path=/', 'text/html; charset=utf-8',
'text/html; charset=utf-8', '10', 'W/"a-eda64de5"', 'OK', 'Express',
'application/json', 'application/json; charset=utf-8', '2', 'W/"2-d4cbb29"',
'OK', 'Express', 'X-HTTP-Method-Override', 'sessionid=; Path=/', 'Express',
'sessionid=; Path=/,sessionid=6b059402-d62f-4e6f-b3dd-ce5b9e487c39; Path=/',
'text/html; charset=utf-8', 'text/html; charset=utf-8', '9', 'OK',
'sessionid=; Path=/', 'text/html; charset=utf-8',
'text/html; charset=utf-8', '10', 'W/"a-eda64de5"', 'OK', 'Express',
'Express', 'X-HTTP-Method-Override', 'sessionid=; Path=/',
'application/json'
],

// Put it here so the benchmark result lines will not be super long.
LONG_AND_INVALID: ['Here is a value that is really a folded header ' +
'value\r\n this should be supported, but it is not currently']
};

const inputs = [
// Valid
'',
'1',
'\t\t\t\t\t\t\t\t\t\tFoo bar baz',
'keep-alive',
'close',
'gzip',
'20091',
'private',
'text/html; charset=utf-8',
'text/plain',
'Sat, 07 May 2016 16:54:48 GMT',
'SAMEORIGIN',
'en-US',

// Invalid
'中文呢', // unicode
'foo\nbar',
'\x7F'
];

const bench = common.createBenchmark(main, {
key: [
// Valid
'',
'1',
'\t\t\t\t\t\t\t\t\t\tFoo bar baz',
'keep-alive',
'close',
'gzip',
'20091',
'private',
'text/html; charset=utf-8',
'text/plain',
'Sat, 07 May 2016 16:54:48 GMT',
'SAMEORIGIN',
'en-US',

// Invalid
'LONG_AND_INVALID',
'中文呢', // unicode
'foo\nbar',
'\x7F'
],
input: inputs.concat(Object.keys(groupedInputs)),
n: [1e6],
});

function main({ n, key }) {
if (key === 'LONG_AND_INVALID') {
key = LONG_AND_INVALID;
function main({ n, input }) {
let inputs = [input];
if (groupedInputs.hasOwnProperty(input)) {
inputs = groupedInputs[input];
}

const len = inputs.length;
bench.start();
for (var i = 0; i < n; i++) {
_checkInvalidHeaderChar(key);
_checkInvalidHeaderChar(inputs[i % len]);
}
bench.end(n);
}
46 changes: 2 additions & 44 deletions lib/_http_common.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,57 +242,15 @@ function checkIsHttpToken(val) {
return tokenRegExp.test(val);
}

const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
/**
* True if val contains an invalid field-vchar
* field-value = *( field-content / obs-fold )
* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
* field-vchar = VCHAR / obs-text
*
* checkInvalidHeaderChar() is currently designed to be inlinable by v8,
* so take care when making changes to the implementation so that the source
* code size does not exceed v8's default max_inlined_source_size setting.
**/
var validHdrChars = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0 - 15
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32 - 47
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48 - 63
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80 - 95
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112 - 127
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128 ...
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // ... 255
];
function checkInvalidHeaderChar(val) {
val += '';
if (val.length < 1)
return false;
if (!validHdrChars[val.charCodeAt(0)])
return true;
if (val.length < 2)
return false;
if (!validHdrChars[val.charCodeAt(1)])
return true;
if (val.length < 3)
return false;
if (!validHdrChars[val.charCodeAt(2)])
return true;
if (val.length < 4)
return false;
if (!validHdrChars[val.charCodeAt(3)])
return true;
for (var i = 4; i < val.length; ++i) {
if (!validHdrChars[val.charCodeAt(i)])
return true;
}
return false;
return headerCharRegex.test(val);
}

module.exports = {
Expand Down