123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- "use strict";
- const { isASCIIHex } = require("./infra");
- function strictlySplitByteSequence(buf, cp) {
- const list = [];
- let last = 0;
- let i = buf.indexOf(cp);
- while (i >= 0) {
- list.push(buf.slice(last, i));
- last = i + 1;
- i = buf.indexOf(cp, last);
- }
- if (last !== buf.length) {
- list.push(buf.slice(last));
- }
- return list;
- }
- function replaceByteInByteSequence(buf, from, to) {
- let i = buf.indexOf(from);
- while (i >= 0) {
- buf[i] = to;
- i = buf.indexOf(from, i + 1);
- }
- return buf;
- }
- function percentEncode(c) {
- let hex = c.toString(16).toUpperCase();
- if (hex.length === 1) {
- hex = "0" + hex;
- }
- return "%" + hex;
- }
- function percentDecode(input) {
- const output = Buffer.alloc(input.byteLength);
- let ptr = 0;
- for (let i = 0; i < input.length; ++i) {
- if (input[i] !== 37 || !isASCIIHex(input[i + 1]) || !isASCIIHex(input[i + 2])) {
- output[ptr++] = input[i];
- } else {
- output[ptr++] = parseInt(input.slice(i + 1, i + 3).toString(), 16);
- i += 2;
- }
- }
- return output.slice(0, ptr);
- }
- function parseUrlencoded(input) {
- const sequences = strictlySplitByteSequence(input, 38);
- const output = [];
- for (const bytes of sequences) {
- if (bytes.length === 0) {
- continue;
- }
- let name;
- let value;
- const indexOfEqual = bytes.indexOf(61);
- if (indexOfEqual >= 0) {
- name = bytes.slice(0, indexOfEqual);
- value = bytes.slice(indexOfEqual + 1);
- } else {
- name = bytes;
- value = Buffer.alloc(0);
- }
- name = replaceByteInByteSequence(Buffer.from(name), 43, 32);
- value = replaceByteInByteSequence(Buffer.from(value), 43, 32);
- output.push([percentDecode(name).toString(), percentDecode(value).toString()]);
- }
- return output;
- }
- function serializeUrlencodedByte(input) {
- let output = "";
- for (const byte of input) {
- if (byte === 32) {
- output += "+";
- } else if (byte === 42 ||
- byte === 45 ||
- byte === 46 ||
- (byte >= 48 && byte <= 57) ||
- (byte >= 65 && byte <= 90) ||
- byte === 95 ||
- (byte >= 97 && byte <= 122)) {
- output += String.fromCodePoint(byte);
- } else {
- output += percentEncode(byte);
- }
- }
- return output;
- }
- function serializeUrlencoded(tuples, encodingOverride = undefined) {
- let encoding = "utf-8";
- if (encodingOverride !== undefined) {
- encoding = encodingOverride;
- }
- let output = "";
- for (const [i, tuple] of tuples.entries()) {
- // TODO: handle encoding override
- const name = serializeUrlencodedByte(Buffer.from(tuple[0]));
- let value = tuple[1];
- if (tuple.length > 2 && tuple[2] !== undefined) {
- if (tuple[2] === "hidden" && name === "_charset_") {
- value = encoding;
- } else if (tuple[2] === "file") {
- // value is a File object
- value = value.name;
- }
- }
- value = serializeUrlencodedByte(Buffer.from(value));
- if (i !== 0) {
- output += "&";
- }
- output += `${name}=${value}`;
- }
- return output;
- }
- module.exports = {
- percentEncode,
- percentDecode,
- // application/x-www-form-urlencoded string parser
- parseUrlencoded(input) {
- return parseUrlencoded(Buffer.from(input));
- },
- // application/x-www-form-urlencoded serializer
- serializeUrlencoded
- };
|