From cbbfbd75de8039af23e2f1fd3a576ca530817251 Mon Sep 17 00:00:00 2001 From: Jesus Seijas Date: Thu, 20 Apr 2017 00:37:56 +0200 Subject: [PATCH 1/4] lib: improve querystring unescapeBuffer perf Refactored the unescapeBuffer function in order to simplify it, and also to improve the performance. The benchmark: ```improvement confidence p.value querystring/querystring-unescapebuffer.js n=1000000 input="%20%21%2..." 18.10 % *** 6.671620e-29 querystring/querystring-unescapebuffer.js n=1000000 input="there%20..." 2.75 % * 1.775320e-02 querystring/querystring-unescapebuffer.js n=1000000 input="there%2Q..." 34.12 % *** 8.074612e-25 querystring/querystring-unescapebuffer.js n=1000000 input="there is..." 27.92 % *** 4.923348e-29 ``` --- lib/querystring.js | 87 ++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 57 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index 1976c8e125ad46..bd11a180deca0d 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -64,70 +64,43 @@ 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 c, c1, n, m; + var maxLength = s.length - 2; + // Flag to know if some hex chars have been decoded + var hasHex = false; + while (index < s.length) { + c = s.charCodeAt(index); + if (c === 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; + if (c === 37 /*'%'*/ && index < maxLength) { + c = s.charCodeAt(++index); + n = unhexTable[c]; + if (n < 0) { + out[outIndex++] = 37; // '%' + } else { + c1 = s.charCodeAt(++index); + m = unhexTable[c1]; + if (m < 0) { + out[outIndex++] = 37; // '%' out[outIndex++] = c; - break; + c = c1; + } else { + hasHex = true; + c = n * 16 + m; } - out[outIndex++] = 16 * n + m; - break; + } } + out[outIndex++] = c; + index++; } - - // TODO support returning arbitrary buffers. - - return out.slice(0, outIndex); + return hasHex ? out.slice(0, outIndex) : out; } - function qsUnescape(s, decodeSpaces) { try { return decodeURIComponent(s); From 917ed0adb3cd1fff360b7a996b7df060b22a7fa2 Mon Sep 17 00:00:00 2001 From: Jesus Seijas Date: Thu, 20 Apr 2017 01:16:51 +0200 Subject: [PATCH 2/4] lib: improve querystring unescapeBuffer perf --- lib/querystring.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index bd11a180deca0d..228fdfcd331ae7 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -80,12 +80,12 @@ function unescapeBuffer(s, decodeSpaces) { if (c === 37 /*'%'*/ && index < maxLength) { c = s.charCodeAt(++index); n = unhexTable[c]; - if (n < 0) { + if !(n >= 0) { out[outIndex++] = 37; // '%' } else { c1 = s.charCodeAt(++index); m = unhexTable[c1]; - if (m < 0) { + if !(m >= 0) { out[outIndex++] = 37; // '%' out[outIndex++] = c; c = c1; @@ -101,6 +101,7 @@ function unescapeBuffer(s, decodeSpaces) { return hasHex ? out.slice(0, outIndex) : out; } + function qsUnescape(s, decodeSpaces) { try { return decodeURIComponent(s); From 52c4a67660307aba7ba495587f8d6353bdd1319a Mon Sep 17 00:00:00 2001 From: Jesus Seijas Date: Thu, 20 Apr 2017 01:23:53 +0200 Subject: [PATCH 3/4] querystring: improve querystring unescapeBuffer perf --- lib/querystring.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index 228fdfcd331ae7..ddf205ae3b2ee7 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -80,12 +80,12 @@ function unescapeBuffer(s, decodeSpaces) { if (c === 37 /*'%'*/ && index < maxLength) { c = s.charCodeAt(++index); n = unhexTable[c]; - if !(n >= 0) { + if (!(n >= 0)) { out[outIndex++] = 37; // '%' } else { c1 = s.charCodeAt(++index); m = unhexTable[c1]; - if !(m >= 0) { + if (!(m >= 0)) { out[outIndex++] = 37; // '%' out[outIndex++] = c; c = c1; From 5fd16cb0ceb19a3e98df0021432ca8d726a4d477 Mon Sep 17 00:00:00 2001 From: Jesus Seijas Date: Wed, 26 Apr 2017 00:29:09 +0200 Subject: [PATCH 4/4] querystring: improve querystring unescapeBuffer perf Rename variables and separate in lines. --- lib/querystring.js | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index ddf205ae3b2ee7..dd4d0a13e00c05 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -66,36 +66,39 @@ function unescapeBuffer(s, decodeSpaces) { var out = Buffer.allocUnsafe(s.length); var index = 0; var outIndex = 0; - var c, c1, n, m; + 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) { - c = s.charCodeAt(index); - if (c === 43 /*'+'*/ && decodeSpaces) { + currentChar = s.charCodeAt(index); + if (currentChar === 43 /*'+'*/ && decodeSpaces) { out[outIndex++] = 32; // ' ' index++; continue; } - if (c === 37 /*'%'*/ && index < maxLength) { - c = s.charCodeAt(++index); - n = unhexTable[c]; - if (!(n >= 0)) { + if (currentChar === 37 /*'%'*/ && index < maxLength) { + currentChar = s.charCodeAt(++index); + hexHigh = unhexTable[currentChar]; + if (!(hexHigh >= 0)) { out[outIndex++] = 37; // '%' } else { - c1 = s.charCodeAt(++index); - m = unhexTable[c1]; - if (!(m >= 0)) { + nextChar = s.charCodeAt(++index); + hexLow = unhexTable[nextChar]; + if (!(hexLow >= 0)) { out[outIndex++] = 37; // '%' - out[outIndex++] = c; - c = c1; + out[outIndex++] = currentChar; + currentChar = nextChar; } else { hasHex = true; - c = n * 16 + m; + currentChar = hexHigh * 16 + hexLow; } } } - out[outIndex++] = c; + out[outIndex++] = currentChar; index++; } return hasHex ? out.slice(0, outIndex) : out;