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