#[cfg(feature = "multipart")] use super::multipart::Form; /// dox use bytes::Bytes; use js_sys::{Uint8Array}; use std::fmt; use wasm_bindgen::JsValue; /// The body of a `Request`. /// /// In most cases, this is not needed directly, as the /// [`RequestBuilder.body`][builder] method uses `Into`, which allows /// passing many things (like a string or vector of bytes). /// /// [builder]: ./struct.RequestBuilder.html#method.body pub struct Body { inner: Inner, } enum Inner { Bytes(Bytes), #[cfg(feature = "multipart")] Multipart(Form), } impl Body { /// Returns a reference to the internal data of the `Body`. /// /// `None` is returned, if the underlying data is a multipart form. #[inline] pub fn as_bytes(&self) -> Option<&[u8]> { match &self.inner { Inner::Bytes(bytes) => Some(bytes.as_ref()), #[cfg(feature = "multipart")] Inner::Multipart(_) => None, } } pub(crate) fn to_js_value(&self) -> crate::Result { match &self.inner { Inner::Bytes(body_bytes) => { let body_bytes: &[u8] = body_bytes.as_ref(); let body_uint8_array: Uint8Array = body_bytes.into(); let js_value: &JsValue = body_uint8_array.as_ref(); Ok(js_value.to_owned()) } #[cfg(feature = "multipart")] Inner::Multipart(form) => { let form_data = form.to_form_data()?; let js_value: &JsValue = form_data.as_ref(); Ok(js_value.to_owned()) } } } #[inline] #[cfg(feature = "multipart")] pub(crate) fn from_form(f: Form) -> Body { Self { inner: Inner::Multipart(f), } } pub(crate) fn is_empty(&self) -> bool { match &self.inner { Inner::Bytes(bytes) => bytes.is_empty(), #[cfg(feature = "multipart")] Inner::Multipart(form) => form.is_empty(), } } pub(crate) fn try_clone(&self) -> Option { match &self.inner { Inner::Bytes(bytes) => Some(Self { inner: Inner::Bytes(bytes.clone()), }), #[cfg(feature = "multipart")] Inner::Multipart(_) => None, } } } impl From for Body { #[inline] fn from(bytes: Bytes) -> Body { Body { inner: Inner::Bytes(bytes), } } } impl From> for Body { #[inline] fn from(vec: Vec) -> Body { Body { inner: Inner::Bytes(vec.into()), } } } impl From<&'static [u8]> for Body { #[inline] fn from(s: &'static [u8]) -> Body { Body { inner: Inner::Bytes(Bytes::from_static(s)), } } } impl From for Body { #[inline] fn from(s: String) -> Body { Body { inner: Inner::Bytes(s.into()), } } } impl From<&'static str> for Body { #[inline] fn from(s: &'static str) -> Body { s.as_bytes().into() } } impl fmt::Debug for Body { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Body").finish() } } #[cfg(test)] mod tests { // use js_sys::{Array, Uint8Array}; use wasm_bindgen::{prelude::*}; use wasm_bindgen_test::*; wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); #[wasm_bindgen] extern "C" { // Use `js_namespace` here to bind `console.log(..)` instead of just // `log(..)` #[wasm_bindgen(js_namespace = console)] fn log(s: String); } #[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; let body_value = "TEST"; 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 text_promise = js_req.text().expect("could not get text promise"); let text = crate::wasm::promise::(text_promise).await.expect("could not get request body as text"); assert_eq!(text.as_string().expect("text is not a string"), body_value); } }