From 8a2a763f13c7a940c7188bfee10556a9a815bb99 Mon Sep 17 00:00:00 2001 From: Brian White Date: Sun, 18 Dec 2016 21:21:57 -0500 Subject: [PATCH] http: improve validation performance The new table-based lookups perform significantly better for the common cases (checking latin1 characters). PR-URL: https://github.com/nodejs/node/pull/6533 Reviewed-By: Matteo Collina Reviewed-By: James M Snell Reviewed-By: Fedor Indutny Reviewed-By: Benjamin Gruenbaum --- lib/_http_common.js | 100 ++++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 41 deletions(-) diff --git a/lib/_http_common.js b/lib/_http_common.js index b0767fd43ca1b8..2ce523fe6298bd 100644 --- a/lib/_http_common.js +++ b/lib/_http_common.js @@ -246,44 +246,44 @@ exports.httpSocketSetup = httpSocketSetup; * 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. **/ -function isValidTokenChar(ch) { - if (ch >= 94 && ch <= 122) - return true; - if (ch >= 65 && ch <= 90) - return true; - if (ch === 45) - return true; - if (ch >= 48 && ch <= 57) - return true; - if (ch === 34 || ch === 40 || ch === 41 || ch === 44) +var validTokens = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 + 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63 + 0, 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, 0, 0, 0, 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, 0, 1, 0, 1, 0, // 112 - 127 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128 ... + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // ... 255 +]; +function checkIsHttpToken(val) { + if (typeof val !== 'string' || val.length === 0) + return false; + if (!validTokens[val.charCodeAt(0)]) return false; - if (ch >= 33 && ch <= 46) + if (val.length < 2) return true; - if (ch === 124 || ch === 126) + if (!validTokens[val.charCodeAt(1)]) + return false; + if (val.length < 3) return true; - return false; -} -function checkIsHttpToken(val) { - if (typeof val !== 'string' || val.length === 0) + if (!validTokens[val.charCodeAt(2)]) return false; - if (!isValidTokenChar(val.charCodeAt(0))) + if (val.length < 4) + return true; + if (!validTokens[val.charCodeAt(3)]) return false; - const len = val.length; - if (len > 1) { - if (!isValidTokenChar(val.charCodeAt(1))) + for (var i = 4; i < val.length; ++i) { + if (!validTokens[val.charCodeAt(i)]) return false; - if (len > 2) { - if (!isValidTokenChar(val.charCodeAt(2))) - return false; - if (len > 3) { - if (!isValidTokenChar(val.charCodeAt(3))) - return false; - for (var i = 4; i < len; i++) { - if (!isValidTokenChar(val.charCodeAt(i))) - return false; - } - } - } } return true; } @@ -299,26 +299,44 @@ exports._checkIsHttpToken = checkIsHttpToken; * 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; - var c = val.charCodeAt(0); - if ((c <= 31 && c !== 9) || c > 255 || c === 127) + if (!validHdrChars[val.charCodeAt(0)]) return true; if (val.length < 2) return false; - c = val.charCodeAt(1); - if ((c <= 31 && c !== 9) || c > 255 || c === 127) + if (!validHdrChars[val.charCodeAt(1)]) return true; if (val.length < 3) return false; - c = val.charCodeAt(2); - if ((c <= 31 && c !== 9) || c > 255 || c === 127) + if (!validHdrChars[val.charCodeAt(2)]) + return true; + if (val.length < 4) + return false; + if (!validHdrChars[val.charCodeAt(3)]) return true; - for (var i = 3; i < val.length; ++i) { - c = val.charCodeAt(i); - if ((c <= 31 && c !== 9) || c > 255 || c === 127) + for (var i = 4; i < val.length; ++i) { + if (!validHdrChars[val.charCodeAt(i)]) return true; } return false;