wasm: fix standalone/multipart body conversion to JsValue (#1364)
This commit is contained in:
@@ -166,7 +166,8 @@ features = [
|
||||
"Blob",
|
||||
"BlobPropertyBag",
|
||||
"ServiceWorkerGlobalScope",
|
||||
"RequestCredentials"
|
||||
"RequestCredentials",
|
||||
"File"
|
||||
]
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
||||
|
||||
136
src/wasm/body.rs
136
src/wasm/body.rs
@@ -19,8 +19,12 @@ pub struct Body {
|
||||
|
||||
enum Inner {
|
||||
Bytes(Bytes),
|
||||
/// MultipartForm holds a multipart/form-data body.
|
||||
#[cfg(feature = "multipart")]
|
||||
Multipart(Form),
|
||||
MultipartForm(Form),
|
||||
/// MultipartPart holds the body of a multipart/form-data part.
|
||||
#[cfg(feature = "multipart")]
|
||||
MultipartPart(Bytes),
|
||||
}
|
||||
|
||||
impl Body {
|
||||
@@ -32,7 +36,9 @@ impl Body {
|
||||
match &self.inner {
|
||||
Inner::Bytes(bytes) => Some(bytes.as_ref()),
|
||||
#[cfg(feature = "multipart")]
|
||||
Inner::Multipart(_) => None,
|
||||
Inner::MultipartForm(_) => None,
|
||||
#[cfg(feature = "multipart")]
|
||||
Inner::MultipartPart(bytes) => Some(bytes.as_ref()),
|
||||
}
|
||||
}
|
||||
pub(crate) fn to_js_value(&self) -> crate::Result<JsValue> {
|
||||
@@ -44,11 +50,20 @@ impl Body {
|
||||
Ok(js_value.to_owned())
|
||||
}
|
||||
#[cfg(feature = "multipart")]
|
||||
Inner::Multipart(form) => {
|
||||
Inner::MultipartForm(form) => {
|
||||
let form_data = form.to_form_data()?;
|
||||
let js_value: &JsValue = form_data.as_ref();
|
||||
Ok(js_value.to_owned())
|
||||
}
|
||||
#[cfg(feature = "multipart")]
|
||||
Inner::MultipartPart(body_bytes) => {
|
||||
let body_bytes: &[u8] = body_bytes.as_ref();
|
||||
let body_uint8_array: Uint8Array = body_bytes.into();
|
||||
let body_array = js_sys::Array::new();
|
||||
body_array.push(&body_uint8_array);
|
||||
let js_value: &JsValue = body_array.as_ref();
|
||||
Ok(js_value.to_owned())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +71,23 @@ impl Body {
|
||||
#[cfg(feature = "multipart")]
|
||||
pub(crate) fn from_form(f: Form) -> Body {
|
||||
Self {
|
||||
inner: Inner::Multipart(f),
|
||||
inner: Inner::MultipartForm(f),
|
||||
}
|
||||
}
|
||||
|
||||
/// into_part turns a regular body into the body of a mutlipart/form-data part.
|
||||
#[cfg(feature = "multipart")]
|
||||
pub(crate) fn into_part(self) -> Body {
|
||||
match self.inner {
|
||||
Inner::Bytes(bytes) => Self {
|
||||
inner: Inner::MultipartPart(bytes),
|
||||
},
|
||||
Inner::MultipartForm(form) => Self {
|
||||
inner: Inner::MultipartForm(form),
|
||||
},
|
||||
Inner::MultipartPart(bytes) => Self {
|
||||
inner: Inner::MultipartPart(bytes),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +95,9 @@ impl Body {
|
||||
match &self.inner {
|
||||
Inner::Bytes(bytes) => bytes.is_empty(),
|
||||
#[cfg(feature = "multipart")]
|
||||
Inner::Multipart(form) => form.is_empty(),
|
||||
Inner::MultipartForm(form) => form.is_empty(),
|
||||
#[cfg(feature = "multipart")]
|
||||
Inner::MultipartPart(bytes) => bytes.is_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +107,11 @@ impl Body {
|
||||
inner: Inner::Bytes(bytes.clone()),
|
||||
}),
|
||||
#[cfg(feature = "multipart")]
|
||||
Inner::Multipart(_) => None,
|
||||
Inner::MultipartForm(_) => None,
|
||||
#[cfg(feature = "multipart")]
|
||||
Inner::MultipartPart(bytes) => Some(Self {
|
||||
inner: Inner::MultipartPart(bytes.clone()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,7 +167,8 @@ impl fmt::Debug for Body {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// use js_sys::{Array, Uint8Array};
|
||||
use crate::Body;
|
||||
use js_sys::Uint8Array;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
@@ -146,16 +184,12 @@ mod tests {
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
async fn test_body() {
|
||||
use crate::Body;
|
||||
|
||||
let body = Body::from("TEST");
|
||||
assert_eq!([84, 69, 83, 84], body.as_bytes().unwrap());
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
async fn test_body_js() {
|
||||
use crate::Body;
|
||||
|
||||
async fn test_body_js_static_str() {
|
||||
let body_value = "TEST";
|
||||
let body = Body::from(body_value);
|
||||
|
||||
@@ -176,4 +210,82 @@ mod tests {
|
||||
|
||||
assert_eq!(text.as_string().expect("text is not a string"), body_value);
|
||||
}
|
||||
#[wasm_bindgen_test]
|
||||
async fn test_body_js_string() {
|
||||
let body_value = "TEST".to_string();
|
||||
let body = Body::from(body_value.clone());
|
||||
|
||||
let mut init = web_sys::RequestInit::new();
|
||||
init.method("POST");
|
||||
init.body(Some(
|
||||
body.to_js_value()
|
||||
.expect("could not convert body to JsValue")
|
||||
.as_ref(),
|
||||
));
|
||||
|
||||
let js_req = web_sys::Request::new_with_str_and_init("", &init)
|
||||
.expect("could not create JS request");
|
||||
let text_promise = js_req.text().expect("could not get text promise");
|
||||
let text = crate::wasm::promise::<JsValue>(text_promise)
|
||||
.await
|
||||
.expect("could not get request body as text");
|
||||
|
||||
assert_eq!(text.as_string().expect("text is not a string"), body_value);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
async fn test_body_js_static_u8_slice() {
|
||||
let body_value: &'static [u8] = b"\x00\x42";
|
||||
let body = Body::from(body_value);
|
||||
|
||||
let mut init = web_sys::RequestInit::new();
|
||||
init.method("POST");
|
||||
init.body(Some(
|
||||
body.to_js_value()
|
||||
.expect("could not convert body to JsValue")
|
||||
.as_ref(),
|
||||
));
|
||||
|
||||
let js_req = web_sys::Request::new_with_str_and_init("", &init)
|
||||
.expect("could not create JS request");
|
||||
|
||||
let array_buffer_promise = js_req
|
||||
.array_buffer()
|
||||
.expect("could not get array_buffer promise");
|
||||
let array_buffer = crate::wasm::promise::<JsValue>(array_buffer_promise)
|
||||
.await
|
||||
.expect("could not get request body as array buffer");
|
||||
|
||||
let v = Uint8Array::new(&array_buffer).to_vec();
|
||||
|
||||
assert_eq!(v, body_value);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
async fn test_body_js_vec_u8() {
|
||||
let body_value = vec![0u8, 42];
|
||||
let body = Body::from(body_value.clone());
|
||||
|
||||
let mut init = web_sys::RequestInit::new();
|
||||
init.method("POST");
|
||||
init.body(Some(
|
||||
body.to_js_value()
|
||||
.expect("could not convert body to JsValue")
|
||||
.as_ref(),
|
||||
));
|
||||
|
||||
let js_req = web_sys::Request::new_with_str_and_init("", &init)
|
||||
.expect("could not create JS request");
|
||||
|
||||
let array_buffer_promise = js_req
|
||||
.array_buffer()
|
||||
.expect("could not get array_buffer promise");
|
||||
let array_buffer = crate::wasm::promise::<JsValue>(array_buffer_promise)
|
||||
.await
|
||||
.expect("could not get request body as array buffer");
|
||||
|
||||
let v = Uint8Array::new(&array_buffer).to_vec();
|
||||
|
||||
assert_eq!(v, body_value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ impl Part {
|
||||
fn new(value: Body) -> Part {
|
||||
Part {
|
||||
meta: PartMetadata::new(),
|
||||
value,
|
||||
value: value.into_part(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ impl Part {
|
||||
}
|
||||
|
||||
// BUG: the return value of to_js_value() is not valid if
|
||||
// it is a Multipart variant.
|
||||
// it is a MultipartForm variant.
|
||||
let js_value = self.value.to_js_value()?;
|
||||
Blob::new_with_u8_array_sequence_and_options(&js_value, &properties)
|
||||
.map_err(crate::error::wasm)
|
||||
@@ -277,4 +277,84 @@ impl PartMetadata {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {}
|
||||
mod tests {
|
||||
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
async fn test_multipart_js() {
|
||||
use super::{Form, Part};
|
||||
use js_sys::Uint8Array;
|
||||
use wasm_bindgen::JsValue;
|
||||
use web_sys::{File, FormData};
|
||||
|
||||
let text_file_name = "test.txt";
|
||||
let text_file_type = "text/plain";
|
||||
let text_content = "TEST";
|
||||
let text_part = Part::text(text_content)
|
||||
.file_name(text_file_name)
|
||||
.mime_str(text_file_type)
|
||||
.expect("invalid mime type");
|
||||
|
||||
let binary_file_name = "binary.bin";
|
||||
let binary_file_type = "application/octet-stream";
|
||||
let binary_content = vec![0u8, 42];
|
||||
let binary_part = Part::bytes(binary_content.clone())
|
||||
.file_name(binary_file_name)
|
||||
.mime_str(binary_file_type)
|
||||
.expect("invalid mime type");
|
||||
|
||||
let text_name = "text part";
|
||||
let binary_name = "binary part";
|
||||
let form = Form::new()
|
||||
.part(text_name, text_part)
|
||||
.part(binary_name, binary_part);
|
||||
|
||||
let mut init = web_sys::RequestInit::new();
|
||||
init.method("POST");
|
||||
init.body(Some(
|
||||
form.to_form_data()
|
||||
.expect("could not convert to FormData")
|
||||
.as_ref(),
|
||||
));
|
||||
|
||||
let js_req = web_sys::Request::new_with_str_and_init("", &init)
|
||||
.expect("could not create JS request");
|
||||
|
||||
let form_data_promise = js_req.form_data().expect("could not get form_data promise");
|
||||
|
||||
let form_data = crate::wasm::promise::<FormData>(form_data_promise)
|
||||
.await
|
||||
.expect("could not get body as form data");
|
||||
|
||||
// check text part
|
||||
let text_file = File::from(form_data.get(text_name));
|
||||
assert_eq!(text_file.name(), text_file_name);
|
||||
assert_eq!(text_file.type_(), text_file_type);
|
||||
|
||||
let text_promise = text_file.text();
|
||||
let text = crate::wasm::promise::<JsValue>(text_promise)
|
||||
.await
|
||||
.expect("could not get text body as text");
|
||||
assert_eq!(
|
||||
text.as_string().expect("text is not a string"),
|
||||
text_content
|
||||
);
|
||||
|
||||
// check binary part
|
||||
let binary_file = File::from(form_data.get(binary_name));
|
||||
assert_eq!(binary_file.name(), binary_file_name);
|
||||
assert_eq!(binary_file.type_(), binary_file_type);
|
||||
|
||||
let binary_array_buffer_promise = binary_file.array_buffer();
|
||||
let array_buffer = crate::wasm::promise::<JsValue>(binary_array_buffer_promise)
|
||||
.await
|
||||
.expect("could not get request body as array buffer");
|
||||
|
||||
let binary = Uint8Array::new(&array_buffer).to_vec();
|
||||
|
||||
assert_eq!(binary, binary_content);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user