From 19685eac65491b54ff5eedb3360fa287a8caa51c Mon Sep 17 00:00:00 2001 From: Jesus Seijas Date: Thu, 20 Apr 2017 00:37:56 +0200 Subject: [PATCH] querystring: improve unescapeBuffer() performance Refactored the `unescapeBuffer` function in order to simplify it, and also to improve the performance. PR-URL: https://github.com/nodejs/node/pull/12525 Reviewed-By: Luigi Pinca Reviewed-By: Brian White --- lib/querystring.js | 91 +++++++++++++++++----------------------------- 1 file changed, 34 insertions(+), 57 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index 1976c8e125..dd4d0a13e0 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -64,67 +64,44 @@ const unhexTable = [ // a safe fast alternative to decodeURIComponent function unescapeBuffer(s, decodeSpaces) { var out = Buffer.allocUnsafe(s.length); - var state = 0; - var n, m, hexchar, c; - - for (var inIndex = 0, outIndex = 0; ; inIndex++) { - if (inIndex < s.length) { - c = s.charCodeAt(inIndex); - } else { - if (state > 0) { - out[outIndex++] = 37/*%*/; - if (state === 2) - out[outIndex++] = hexchar; - } - break; + var index = 0; + var outIndex = 0; + var currentChar; + var nextChar; + var hexHigh; + var hexLow; + var maxLength = s.length - 2; + // Flag to know if some hex chars have been decoded + var hasHex = false; + while (index < s.length) { + currentChar = s.charCodeAt(index); + if (currentChar === 43 /*'+'*/ && decodeSpaces) { + out[outIndex++] = 32; // ' ' + index++; + continue; } - switch (state) { - case 0: // Any character - switch (c) { - case 37: // '%' - n = 0; - m = 0; - state = 1; - break; - case 43: // '+' - if (decodeSpaces) - c = 32; // ' ' - // falls through - default: - out[outIndex++] = c; - break; - } - break; - - case 1: // First hex digit - hexchar = c; - n = unhexTable[c]; - if (!(n >= 0)) { - out[outIndex++] = 37/*%*/; - out[outIndex++] = c; - state = 0; - break; - } - state = 2; - break; - - case 2: // Second hex digit - state = 0; - m = unhexTable[c]; - if (!(m >= 0)) { - out[outIndex++] = 37/*%*/; - out[outIndex++] = hexchar; - out[outIndex++] = c; - break; + if (currentChar === 37 /*'%'*/ && index < maxLength) { + currentChar = s.charCodeAt(++index); + hexHigh = unhexTable[currentChar]; + if (!(hexHigh >= 0)) { + out[outIndex++] = 37; // '%' + } else { + nextChar = s.charCodeAt(++index); + hexLow = unhexTable[nextChar]; + if (!(hexLow >= 0)) { + out[outIndex++] = 37; // '%' + out[outIndex++] = currentChar; + currentChar = nextChar; + } else { + hasHex = true; + currentChar = hexHigh * 16 + hexLow; } - out[outIndex++] = 16 * n + m; - break; + } } + out[outIndex++] = currentChar; + index++; } - - // TODO support returning arbitrary buffers. - - return out.slice(0, outIndex); + return hasHex ? out.slice(0, outIndex) : out; }