fix: fix issue for multipart/form-data and cookie header (#4172)
* fix(multipart-formdata): fix type for data variable * fix(multipart-formdata): fix parameter filter for unsetted file * fix(multipart-formdata): add mime type for sending file * fix(multipart-formdata): add application/octet-stream by default mimetype * fix(multipart-formdata): remove content-type: multipart/form-data header * fix(multipart-formdata): remove cookie cookie header if not present * fix(multipart-formdata): fix content-type filter --------- Co-authored-by: Dmitry Mukovkin <d.mukovkin@cft.ru>
This commit is contained in:
@@ -320,7 +320,13 @@ function getFinalBodyFromRequest(
|
|||||||
if (request.body.contentType === "multipart/form-data") {
|
if (request.body.contentType === "multipart/form-data") {
|
||||||
return pipe(
|
return pipe(
|
||||||
request.body.body ?? [],
|
request.body.body ?? [],
|
||||||
A.filter((x) => (x.key !== "" || x.isFile) && x.active), // Remove empty keys
|
A.filter(
|
||||||
|
(x) =>
|
||||||
|
x.key !== "" &&
|
||||||
|
x.active &&
|
||||||
|
(typeof x.value === "string" ||
|
||||||
|
(x.value.length > 0 && x.value[0] instanceof File))
|
||||||
|
), // Remove empty keys and unsetted file
|
||||||
|
|
||||||
// Sort files down
|
// Sort files down
|
||||||
arraySort((a, b) => {
|
arraySort((a, b) => {
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ enum FormDataValue {
|
|||||||
Text(String),
|
Text(String),
|
||||||
File {
|
File {
|
||||||
filename: String,
|
filename: String,
|
||||||
data: Vec<u8>
|
data: Vec<u8>,
|
||||||
|
mime: String
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,11 +113,12 @@ fn convert_bodydef_to_req_action(req: &RequestDef) -> Option<ReqBodyAction> {
|
|||||||
for entry in entries {
|
for entry in entries {
|
||||||
form = match &entry.value {
|
form = match &entry.value {
|
||||||
FormDataValue::Text(value) => form.text(entry.key.clone(), value.clone()),
|
FormDataValue::Text(value) => form.text(entry.key.clone(), value.clone()),
|
||||||
FormDataValue::File { filename, data } =>
|
FormDataValue::File { filename, data, mime } =>
|
||||||
form.part(
|
form.part(
|
||||||
entry.key.clone(),
|
entry.key.clone(),
|
||||||
reqwest::multipart::Part::bytes(data.clone())
|
reqwest::multipart::Part::bytes(data.clone())
|
||||||
.file_name(filename.clone())
|
.file_name(filename.clone())
|
||||||
|
.mime_str(mime.as_str()).expect("Error while setting File enum")
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { CookieJarService } from "@hoppscotch/common/services/cookie-jar.service"
|
import { CookieJarService } from "@hoppscotch/common/services/cookie-jar.service"
|
||||||
import { Interceptor, InterceptorError, NetworkResponse, RequestRunResult } from "@hoppscotch/common/services/interceptor.service"
|
import { Interceptor, InterceptorError, RequestRunResult } from "@hoppscotch/common/services/interceptor.service"
|
||||||
import { Service } from "dioc"
|
import { Service } from "dioc"
|
||||||
import { cloneDeep } from "lodash-es"
|
import { cloneDeep } from "lodash-es"
|
||||||
import { invoke } from "@tauri-apps/api/tauri"
|
import { invoke } from "@tauri-apps/api/tauri"
|
||||||
@@ -21,7 +21,8 @@ type FormDataValue =
|
|||||||
| {
|
| {
|
||||||
File: {
|
File: {
|
||||||
filename: string,
|
filename: string,
|
||||||
data: Uint8Array
|
data: number[],
|
||||||
|
mime: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,12 +125,15 @@ async function processBody(axiosReq: AxiosRequestConfig): Promise<BodyDef | null
|
|||||||
value: { Text: value }
|
value: { Text: value }
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
const mime = value.type !== "" ? value.type : "application/octet-stream"
|
||||||
|
|
||||||
entries.push({
|
entries.push({
|
||||||
key,
|
key,
|
||||||
value: {
|
value: {
|
||||||
File: {
|
File: {
|
||||||
filename: value.name,
|
filename: value.name,
|
||||||
data: new Uint8Array(await value.arrayBuffer())
|
data: Array.from(new Uint8Array(await value.arrayBuffer())),
|
||||||
|
mime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -184,6 +188,7 @@ async function convertToRequestDef(
|
|||||||
method: axiosReq.method ?? "GET",
|
method: axiosReq.method ?? "GET",
|
||||||
endpoint: axiosReq.url ?? "",
|
endpoint: axiosReq.url ?? "",
|
||||||
headers: Object.entries(axiosReq.headers ?? {})
|
headers: Object.entries(axiosReq.headers ?? {})
|
||||||
|
.filter(([key, value]) => !(key.toLowerCase() === "content-type" && value.toLowerCase() === "multipart/form-data")) // Removing header, because this header will be set by reqwest
|
||||||
.map(([key, value]): KeyValuePair => ({ key, value })),
|
.map(([key, value]): KeyValuePair => ({ key, value })),
|
||||||
parameters: Object.entries(axiosReq.params as Record<string, string> ?? {})
|
parameters: Object.entries(axiosReq.params as Record<string, string> ?? {})
|
||||||
.map(([key, value]): KeyValuePair => ({ key, value })),
|
.map(([key, value]): KeyValuePair => ({ key, value })),
|
||||||
@@ -394,9 +399,11 @@ export class NativeInterceptorService extends Service implements Interceptor {
|
|||||||
new URL(processedReq.url!)
|
new URL(processedReq.url!)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (relevantCookies.length > 0) {
|
||||||
processedReq.headers["Cookie"] = relevantCookies
|
processedReq.headers["Cookie"] = relevantCookies
|
||||||
.map((cookie) => `${cookie.name!}=${cookie.value!}`)
|
.map((cookie) => `${cookie.name!}=${cookie.value!}`)
|
||||||
.join(";")
|
.join(";")
|
||||||
|
}
|
||||||
|
|
||||||
const reqID = this.reqIDTicker++;
|
const reqID = this.reqIDTicker++;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user