|
1 | 1 | 'use strict';
|
2 | 2 |
|
3 | 3 | const util = require('util');
|
4 |
| -const { StorageObject } = require('internal/querystring'); |
| 4 | +const { hexTable, StorageObject } = require('internal/querystring'); |
5 | 5 | const binding = process.binding('url');
|
6 | 6 | const context = Symbol('context');
|
7 | 7 | const cannotBeBase = Symbol('cannot-be-base');
|
@@ -594,18 +594,99 @@ function getParamsFromObject(obj) {
|
594 | 594 | return values;
|
595 | 595 | }
|
596 | 596 |
|
597 |
| -function getObjectFromParams(array) { |
598 |
| - const obj = new StorageObject(); |
599 |
| - for (var i = 0; i < array.length; i += 2) { |
600 |
| - const name = array[i]; |
601 |
| - const value = array[i + 1]; |
602 |
| - if (obj[name]) { |
603 |
| - obj[name].push(value); |
604 |
| - } else { |
605 |
| - obj[name] = [value]; |
| 597 | +// Adapted from querystring's implementation. |
| 598 | +// Ref: https://url.spec.whatwg.org/#concept-urlencoded-byte-serializer |
| 599 | +const noEscape = [ |
| 600 | +//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F |
| 601 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00 - 0x0F |
| 602 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10 - 0x1F |
| 603 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, // 0x20 - 0x2F |
| 604 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 0x30 - 0x3F |
| 605 | + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 - 0x4F |
| 606 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 0x50 - 0x5F |
| 607 | + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 0x6F |
| 608 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 // 0x70 - 0x7F |
| 609 | +]; |
| 610 | + |
| 611 | +// Special version of hexTable that uses `+` for U+0020 SPACE. |
| 612 | +const paramHexTable = hexTable.slice(); |
| 613 | +paramHexTable[0x20] = '+'; |
| 614 | + |
| 615 | +function escapeParam(str) { |
| 616 | + const len = str.length; |
| 617 | + if (len === 0) |
| 618 | + return ''; |
| 619 | + |
| 620 | + var out = ''; |
| 621 | + var lastPos = 0; |
| 622 | + |
| 623 | + for (var i = 0; i < len; i++) { |
| 624 | + var c = str.charCodeAt(i); |
| 625 | + |
| 626 | + // ASCII |
| 627 | + if (c < 0x80) { |
| 628 | + if (noEscape[c] === 1) |
| 629 | + continue; |
| 630 | + if (lastPos < i) |
| 631 | + out += str.slice(lastPos, i); |
| 632 | + lastPos = i + 1; |
| 633 | + out += paramHexTable[c]; |
| 634 | + continue; |
| 635 | + } |
| 636 | + |
| 637 | + if (lastPos < i) |
| 638 | + out += str.slice(lastPos, i); |
| 639 | + |
| 640 | + // Multi-byte characters ... |
| 641 | + if (c < 0x800) { |
| 642 | + lastPos = i + 1; |
| 643 | + out += paramHexTable[0xC0 | (c >> 6)] + |
| 644 | + paramHexTable[0x80 | (c & 0x3F)]; |
| 645 | + continue; |
| 646 | + } |
| 647 | + if (c < 0xD800 || c >= 0xE000) { |
| 648 | + lastPos = i + 1; |
| 649 | + out += paramHexTable[0xE0 | (c >> 12)] + |
| 650 | + paramHexTable[0x80 | ((c >> 6) & 0x3F)] + |
| 651 | + paramHexTable[0x80 | (c & 0x3F)]; |
| 652 | + continue; |
606 | 653 | }
|
| 654 | + // Surrogate pair |
| 655 | + ++i; |
| 656 | + var c2; |
| 657 | + if (i < len) |
| 658 | + c2 = str.charCodeAt(i) & 0x3FF; |
| 659 | + else { |
| 660 | + // This branch should never happen because all URLSearchParams entries |
| 661 | + // should already be converted to USVString. But, included for |
| 662 | + // completion's sake anyway. |
| 663 | + c2 = 0; |
| 664 | + } |
| 665 | + lastPos = i + 1; |
| 666 | + c = 0x10000 + (((c & 0x3FF) << 10) | c2); |
| 667 | + out += paramHexTable[0xF0 | (c >> 18)] + |
| 668 | + paramHexTable[0x80 | ((c >> 12) & 0x3F)] + |
| 669 | + paramHexTable[0x80 | ((c >> 6) & 0x3F)] + |
| 670 | + paramHexTable[0x80 | (c & 0x3F)]; |
607 | 671 | }
|
608 |
| - return obj; |
| 672 | + if (lastPos === 0) |
| 673 | + return str; |
| 674 | + if (lastPos < len) |
| 675 | + return out + str.slice(lastPos); |
| 676 | + return out; |
| 677 | +} |
| 678 | + |
| 679 | +// application/x-www-form-urlencoded serializer |
| 680 | +// Ref: https://url.spec.whatwg.org/#concept-urlencoded-serializer |
| 681 | +function serializeParams(array) { |
| 682 | + const len = array.length; |
| 683 | + if (len === 0) |
| 684 | + return ''; |
| 685 | + |
| 686 | + var output = `${escapeParam(array[0])}=${escapeParam(array[1])}`; |
| 687 | + for (var i = 2; i < len; i += 2) |
| 688 | + output += `&${escapeParam(array[i])}=${escapeParam(array[i + 1])}`; |
| 689 | + return output; |
609 | 690 | }
|
610 | 691 |
|
611 | 692 | // Mainly to mitigate func-name-matching ESLint rule
|
@@ -990,7 +1071,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
|
990 | 1071 | throw new TypeError('Value of `this` is not a URLSearchParams');
|
991 | 1072 | }
|
992 | 1073 |
|
993 |
| - return querystring.stringify(getObjectFromParams(this[searchParams])); |
| 1074 | + return serializeParams(this[searchParams]); |
994 | 1075 | }
|
995 | 1076 | });
|
996 | 1077 |
|
|
0 commit comments