Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 97ff432

Browse filesBrowse files
mscdexItalo A. Casas
authored andcommitted
querystring: improve unescapeBuffer performance
PR-URL: #10837 Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent f4796d5 commit 97ff432
Copy full SHA for 97ff432

File tree

Expand file treeCollapse file tree

3 files changed

+65
-19
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+65
-19
lines changed
Open diff view settings
Collapse file
+23Lines changed: 23 additions & 0 deletions
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+
}
Collapse file

‎lib/querystring.js‎

Copy file name to clipboardExpand all lines: lib/querystring.js
+35-19Lines changed: 35 additions & 19 deletions
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

Collapse file

‎test/parallel/test-querystring.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-querystring.js
+7Lines changed: 7 additions & 0 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.