Skip to content

Commit 97ff432

Browse files
mscdexitaloacasas
authored andcommitted
querystring: improve unescapeBuffer performance
PR-URL: #10837 Reviewed-By: James M Snell <[email protected]>
1 parent f4796d5 commit 97ff432

File tree

3 files changed

+65
-19
lines changed

3 files changed

+65
-19
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
var common = require('../common.js');
3+
var querystring = require('querystring');
4+
5+
var bench = common.createBenchmark(main, {
6+
input: [
7+
'there is nothing to unescape here',
8+
'there%20are%20several%20spaces%20that%20need%20to%20be%20unescaped',
9+
'there%2Qare%0-fake%escaped values in%%%%this%9Hstring',
10+
'%20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2D%2E%2F%30%31%32%33%34%35%36%37'
11+
],
12+
n: [10e6],
13+
});
14+
15+
function main(conf) {
16+
var input = conf.input;
17+
var n = conf.n | 0;
18+
19+
bench.start();
20+
for (var i = 0; i < n; i += 1)
21+
querystring.unescapeBuffer(input);
22+
bench.end(n);
23+
}

lib/querystring.js

+35-19
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,41 @@ const Buffer = require('buffer').Buffer;
2222
function ParsedQueryString() {}
2323
ParsedQueryString.prototype = Object.create(null);
2424

25-
25+
const unhexTable = [
26+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0 - 15
27+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16 - 31
28+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32 - 47
29+
+0, +1, +2, +3, +4, +5, +6, +7, +8, +9, -1, -1, -1, -1, -1, -1, // 48 - 63
30+
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 64 - 79
31+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80 - 95
32+
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 96 - 111
33+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 112 - 127
34+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128 ...
35+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
36+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
37+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
38+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
39+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
40+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
41+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // ... 255
42+
];
2643
// a safe fast alternative to decodeURIComponent
2744
function unescapeBuffer(s, decodeSpaces) {
2845
var out = Buffer.allocUnsafe(s.length);
2946
var state = 0;
30-
var n, m, hexchar;
47+
var n, m, hexchar, c;
3148

32-
for (var inIndex = 0, outIndex = 0; inIndex <= s.length; inIndex++) {
33-
var c = inIndex < s.length ? s.charCodeAt(inIndex) : NaN;
49+
for (var inIndex = 0, outIndex = 0; ; inIndex++) {
50+
if (inIndex < s.length) {
51+
c = s.charCodeAt(inIndex);
52+
} else {
53+
if (state > 0) {
54+
out[outIndex++] = 37/*%*/;
55+
if (state === 2)
56+
out[outIndex++] = hexchar;
57+
}
58+
break;
59+
}
3460
switch (state) {
3561
case 0: // Any character
3662
switch (c) {
@@ -51,13 +77,8 @@ function unescapeBuffer(s, decodeSpaces) {
5177

5278
case 1: // First hex digit
5379
hexchar = c;
54-
if (c >= 48/*0*/ && c <= 57/*9*/) {
55-
n = c - 48/*0*/;
56-
} else if (c >= 65/*A*/ && c <= 70/*F*/) {
57-
n = c - 65/*A*/ + 10;
58-
} else if (c >= 97/*a*/ && c <= 102/*f*/) {
59-
n = c - 97/*a*/ + 10;
60-
} else {
80+
n = unhexTable[c];
81+
if (!(n >= 0)) {
6182
out[outIndex++] = 37/*%*/;
6283
out[outIndex++] = c;
6384
state = 0;
@@ -68,13 +89,8 @@ function unescapeBuffer(s, decodeSpaces) {
6889

6990
case 2: // Second hex digit
7091
state = 0;
71-
if (c >= 48/*0*/ && c <= 57/*9*/) {
72-
m = c - 48/*0*/;
73-
} else if (c >= 65/*A*/ && c <= 70/*F*/) {
74-
m = c - 65/*A*/ + 10;
75-
} else if (c >= 97/*a*/ && c <= 102/*f*/) {
76-
m = c - 97/*a*/ + 10;
77-
} else {
92+
m = unhexTable[c];
93+
if (!(m >= 0)) {
7894
out[outIndex++] = 37/*%*/;
7995
out[outIndex++] = hexchar;
8096
out[outIndex++] = c;
@@ -87,7 +103,7 @@ function unescapeBuffer(s, decodeSpaces) {
87103

88104
// TODO support returning arbitrary buffers.
89105

90-
return out.slice(0, outIndex - 1);
106+
return out.slice(0, outIndex);
91107
}
92108

93109

test/parallel/test-querystring.js

+7
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,13 @@ assert.strictEqual(0xd8, b[17]);
271271
assert.strictEqual(0xa2, b[18]);
272272
assert.strictEqual(0xe6, b[19]);
273273

274+
assert.strictEqual(qs.unescapeBuffer('a+b', true).toString(), 'a b');
275+
assert.strictEqual(qs.unescapeBuffer('a%').toString(), 'a%');
276+
assert.strictEqual(qs.unescapeBuffer('a%2').toString(), 'a%2');
277+
assert.strictEqual(qs.unescapeBuffer('a%20').toString(), 'a ');
278+
assert.strictEqual(qs.unescapeBuffer('a%2g').toString(), 'a%2g');
279+
assert.strictEqual(qs.unescapeBuffer('a%%').toString(), 'a%%');
280+
274281

275282
// Test custom decode
276283
function demoDecode(str) {

0 commit comments

Comments
 (0)