You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
2.6 KiB
102 lines
2.6 KiB
"use strict"; |
|
const { utf8Encode, utf8DecodeWithoutBOM } = require("./encoding"); |
|
const { percentDecodeBytes, utf8PercentEncodeString, isURLEncodedPercentEncode } = require("./percent-encoding"); |
|
|
|
// https://url.spec.whatwg.org/#concept-urlencoded-parser |
|
function parseUrlencoded(input) { |
|
const sequences = strictlySplitByteSequence(input, 38); |
|
const output = []; |
|
for (const bytes of sequences) { |
|
if (bytes.length === 0) { |
|
continue; |
|
} |
|
|
|
let name, value; |
|
const indexOfEqual = bytes.indexOf(61); |
|
|
|
if (indexOfEqual >= 0) { |
|
name = bytes.slice(0, indexOfEqual); |
|
value = bytes.slice(indexOfEqual + 1); |
|
} else { |
|
name = bytes; |
|
value = new Uint8Array(0); |
|
} |
|
|
|
name = replaceByteInByteSequence(name, 0x2B, 0x20); |
|
value = replaceByteInByteSequence(value, 0x2B, 0x20); |
|
|
|
const nameString = utf8DecodeWithoutBOM(percentDecodeBytes(name)); |
|
const valueString = utf8DecodeWithoutBOM(percentDecodeBytes(value)); |
|
|
|
output.push([nameString, valueString]); |
|
} |
|
return output; |
|
} |
|
|
|
// https://url.spec.whatwg.org/#concept-urlencoded-string-parser |
|
function parseUrlencodedString(input) { |
|
return parseUrlencoded(utf8Encode(input)); |
|
} |
|
|
|
// https://url.spec.whatwg.org/#concept-urlencoded-serializer |
|
function serializeUrlencoded(tuples, encodingOverride = undefined) { |
|
let encoding = "utf-8"; |
|
if (encodingOverride !== undefined) { |
|
// TODO "get the output encoding", i.e. handle encoding labels vs. names. |
|
encoding = encodingOverride; |
|
} |
|
|
|
let output = ""; |
|
for (const [i, tuple] of tuples.entries()) { |
|
// TODO: handle encoding override |
|
|
|
const name = utf8PercentEncodeString(tuple[0], isURLEncodedPercentEncode, true); |
|
|
|
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 = utf8PercentEncodeString(value, isURLEncodedPercentEncode, true); |
|
|
|
if (i !== 0) { |
|
output += "&"; |
|
} |
|
output += `${name}=${value}`; |
|
} |
|
return output; |
|
} |
|
|
|
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; |
|
} |
|
|
|
module.exports = { |
|
parseUrlencodedString, |
|
serializeUrlencoded |
|
};
|
|
|