diff --git a/lib/internal/querystring.js b/lib/internal/querystring.js index 46fdf564dbcc8e..0a984b8cc7b07e 100644 --- a/lib/internal/querystring.js +++ b/lib/internal/querystring.js @@ -93,13 +93,15 @@ function encodeStr(str, noEscapeTable, hexTable) { // This branch should never happen because all URLSearchParams entries // should already be converted to USVString. But, included for // completion's sake anyway. - if (i >= len) + if (i >= len || c >= 0xDC00) throw new ERR_INVALID_URI(); - const c2 = StringPrototypeCharCodeAt(str, i) & 0x3FF; + const c2 = StringPrototypeCharCodeAt(str, i); + if (c2 < 0xDC00 || c2 >= 0xE000) + throw new ERR_INVALID_URI(); lastPos = i + 1; - c = 0x10000 + (((c & 0x3FF) << 10) | c2); + c = 0x10000 + (((c & 0x3FF) << 10) | (c2 & 0x3FF)); out += hexTable[0xF0 | (c >> 18)] + hexTable[0x80 | ((c >> 12) & 0x3F)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + diff --git a/test/parallel/test-querystring-escape.js b/test/parallel/test-querystring-escape.js index 5f3ea3aedc4d05..e15fd510f7d1db 100644 --- a/test/parallel/test-querystring-escape.js +++ b/test/parallel/test-querystring-escape.js @@ -10,17 +10,26 @@ assert.strictEqual(qs.escape({}), '%5Bobject%20Object%5D'); assert.strictEqual(qs.escape([5, 10]), '5%2C10'); assert.strictEqual(qs.escape('Ŋōđĕ'), '%C5%8A%C5%8D%C4%91%C4%95'); assert.strictEqual(qs.escape('testŊōđĕ'), 'test%C5%8A%C5%8D%C4%91%C4%95'); -assert.strictEqual(qs.escape(`${String.fromCharCode(0xD800 + 1)}test`), - '%F0%90%91%B4est'); +assert.strictEqual( + qs.escape(`${String.fromCharCode(0xD800 + 1)}${String.fromCharCode(0xDC00)}`), + '%F0%90%90%80'); -assert.throws( - () => qs.escape(String.fromCharCode(0xD800 + 1)), - { - code: 'ERR_INVALID_URI', - name: 'URIError', - message: 'URI malformed' - } -); +for (const invalid of [ + String.fromCharCode(0xD800 + 1), + `${String.fromCharCode(0xD800 + 1)}test`, + `${String.fromCharCode(0xDC00)}test`, + `${String.fromCharCode(0xD800 + 1)}${String.fromCharCode(0x41)}`, + `${String.fromCharCode(0xD800 + 1)}${String.fromCharCode(0xD800)}`, +]) { + assert.throws( + () => qs.escape(invalid), + { + code: 'ERR_INVALID_URI', + name: 'URIError', + message: 'URI malformed', + }, + ); +} // Using toString for objects assert.strictEqual(