urlencoded.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. "use strict";
  2. const { utf8Encode, utf8DecodeWithoutBOM } = require("./encoding");
  3. const { percentDecodeBytes, utf8PercentEncodeString, isURLEncodedPercentEncode } = require("./percent-encoding");
  4. function p(char) {
  5. return char.codePointAt(0);
  6. }
  7. // https://url.spec.whatwg.org/#concept-urlencoded-parser
  8. function parseUrlencoded(input) {
  9. const sequences = strictlySplitByteSequence(input, p("&"));
  10. const output = [];
  11. for (const bytes of sequences) {
  12. if (bytes.length === 0) {
  13. continue;
  14. }
  15. let name, value;
  16. const indexOfEqual = bytes.indexOf(p("="));
  17. if (indexOfEqual >= 0) {
  18. name = bytes.slice(0, indexOfEqual);
  19. value = bytes.slice(indexOfEqual + 1);
  20. } else {
  21. name = bytes;
  22. value = new Uint8Array(0);
  23. }
  24. name = replaceByteInByteSequence(name, 0x2B, 0x20);
  25. value = replaceByteInByteSequence(value, 0x2B, 0x20);
  26. const nameString = utf8DecodeWithoutBOM(percentDecodeBytes(name));
  27. const valueString = utf8DecodeWithoutBOM(percentDecodeBytes(value));
  28. output.push([nameString, valueString]);
  29. }
  30. return output;
  31. }
  32. // https://url.spec.whatwg.org/#concept-urlencoded-string-parser
  33. function parseUrlencodedString(input) {
  34. return parseUrlencoded(utf8Encode(input));
  35. }
  36. // https://url.spec.whatwg.org/#concept-urlencoded-serializer
  37. function serializeUrlencoded(tuples) {
  38. // TODO: accept and use encoding argument
  39. let output = "";
  40. for (const [i, tuple] of tuples.entries()) {
  41. const name = utf8PercentEncodeString(tuple[0], isURLEncodedPercentEncode, true);
  42. const value = utf8PercentEncodeString(tuple[1], isURLEncodedPercentEncode, true);
  43. if (i !== 0) {
  44. output += "&";
  45. }
  46. output += `${name}=${value}`;
  47. }
  48. return output;
  49. }
  50. function strictlySplitByteSequence(buf, cp) {
  51. const list = [];
  52. let last = 0;
  53. let i = buf.indexOf(cp);
  54. while (i >= 0) {
  55. list.push(buf.slice(last, i));
  56. last = i + 1;
  57. i = buf.indexOf(cp, last);
  58. }
  59. if (last !== buf.length) {
  60. list.push(buf.slice(last));
  61. }
  62. return list;
  63. }
  64. function replaceByteInByteSequence(buf, from, to) {
  65. let i = buf.indexOf(from);
  66. while (i >= 0) {
  67. buf[i] = to;
  68. i = buf.indexOf(from, i + 1);
  69. }
  70. return buf;
  71. }
  72. module.exports = {
  73. parseUrlencodedString,
  74. serializeUrlencoded
  75. };