mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-09-08 19:02:00 +02:00
fix(importer-curl): keep --data-urlencode whole and survive a stray percent (#597)
This commit is contained in:
@@ -506,7 +506,17 @@ function importCommand(parseEntries: string[], workspaceId: string) {
|
||||
form: multipartFormDataFromRaw,
|
||||
};
|
||||
} else if (dataParameters.length > 0 && bodyAsGET) {
|
||||
urlParameters.push(...dataParameters);
|
||||
// `-G` moves the data into the query string, and Yaak encodes url
|
||||
// parameters on send exactly as it encodes the form body below, so this
|
||||
// needs the same decode -- otherwise a `--data-urlencode` value arrives
|
||||
// here already encoded and goes out encoded twice.
|
||||
urlParameters.push(
|
||||
...dataParameters.map((parameter) => ({
|
||||
...parameter,
|
||||
name: decodePercentEncoding(parameter.name),
|
||||
value: decodePercentEncoding(parameter.value),
|
||||
})),
|
||||
);
|
||||
} else if (
|
||||
dataParameters.length > 0 &&
|
||||
(mimeType == null || mimeType === "application/x-www-form-urlencoded")
|
||||
@@ -515,8 +525,8 @@ function importCommand(parseEntries: string[], workspaceId: string) {
|
||||
body = {
|
||||
form: dataParameters.map((parameter) => ({
|
||||
...parameter,
|
||||
name: decodeURIComponent(parameter.name || ""),
|
||||
value: decodeURIComponent(parameter.value || ""),
|
||||
name: decodePercentEncoding(parameter.name),
|
||||
value: decodePercentEncoding(parameter.value),
|
||||
})),
|
||||
};
|
||||
filteredHeaders.push({
|
||||
@@ -593,6 +603,34 @@ interface DataParameter {
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a percent-encoded form value, keeping it as-is when it is not one.
|
||||
*
|
||||
* Yaak's form editor holds decoded values and re-encodes them on send, so a
|
||||
* `-d` value has to be decoded on the way in. But curl sends that value
|
||||
* verbatim and does not require it to be valid percent-encoding: `a=100%` is
|
||||
* an ordinary form value, and `decodeURIComponent` throws URIError on it,
|
||||
* which failed the whole import rather than that one parameter.
|
||||
*/
|
||||
function decodePercentEncoding(value: string | undefined): string {
|
||||
const text = value || "";
|
||||
try {
|
||||
return decodeURIComponent(text);
|
||||
} catch {
|
||||
// Mixed: some of it is percent-encoded and some of it is a stray `%`.
|
||||
// Returning the whole string untouched would leave the encoded part to be
|
||||
// encoded a second time on send, so decode each valid run on its own and
|
||||
// leave the stray byte alone. A run rather than a single escape, because a
|
||||
// non-ASCII character is several escapes that only decode together.
|
||||
return text.replace(/(%[0-9A-Fa-f]{2})+/g, (run) => {
|
||||
try {
|
||||
return decodeURIComponent(run);
|
||||
} catch {
|
||||
return run;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
function pairsToDataParameters(keyedPairs: FlagsByName): DataParameter[] {
|
||||
const dataParameters: DataParameter[] = [];
|
||||
|
||||
@@ -605,7 +643,11 @@ function pairsToDataParameters(keyedPairs: FlagsByName): DataParameter[] {
|
||||
|
||||
for (const p of pairs) {
|
||||
if (typeof p !== "string") continue;
|
||||
const params = p.split("&");
|
||||
// `-d` content really is `&`-separated, so splitting it is right. But
|
||||
// `--data-urlencode` encodes its whole argument — an `&` inside it is
|
||||
// data curl percent-encodes, not a separator, so splitting there turned
|
||||
// one parameter into several and changed what the request sends.
|
||||
const params = flagName === "data-urlencode" ? [p] : p.split("&");
|
||||
for (const param of params) {
|
||||
const [name, value] = splitOnce(param, "=");
|
||||
if (param.startsWith("@")) {
|
||||
|
||||
Reference in New Issue
Block a user