Skip to content

Commit bb516a8

Browse files
FreddieRidellPerseus101
authored andcommitted
Send body and headers correctly in the wasm backend
1 parent 411bd5f commit bb516a8

File tree

2 files changed

+59
-9
lines changed

2 files changed

+59
-9
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ isahc = { version = "0.9", optional = true, default-features = false, features =
4242
js-sys = { version = "0.3.25", optional = true }
4343
wasm-bindgen = { version = "0.2.48", optional = true }
4444
wasm-bindgen-futures = { version = "0.4.5", optional = true }
45+
futures-util = "0.3.1"
4546

4647
[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys]
4748
version = "0.3.25"

src/wasm.rs

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ impl HttpClient for WasmClient {
3434

3535
fn send(&self, req: Request) -> BoxFuture<'static, Result<Response, Self::Error>> {
3636
let fut = Box::pin(async move {
37-
let req = fetch::new(req.method(), req.url());
37+
let req: fetch::Request = fetch::Request::new(req)?;
3838
let mut res = req.send().await?;
3939

4040
let body = res.body_bytes();
@@ -56,7 +56,6 @@ impl HttpClient for WasmClient {
5656
}
5757
}
5858

59-
// This type e
6059
struct InnerFuture {
6160
fut: Pin<Box<dyn Future<Output = Result<Response, io::Error>> + 'static>>,
6261
}
@@ -77,6 +76,8 @@ impl Future for InnerFuture {
7776
}
7877

7978
mod fetch {
79+
use futures_util::io::AsyncReadExt;
80+
use http::request::Parts;
8081
use js_sys::{Array, ArrayBuffer, Reflect, Uint8Array};
8182
use wasm_bindgen::JsCast;
8283
use wasm_bindgen_futures::JsFuture;
@@ -85,27 +86,75 @@ mod fetch {
8586

8687
use std::io;
8788
use std::iter::{IntoIterator, Iterator};
89+
use std::pin::Pin;
8890

8991
/// Create a new fetch request.
90-
pub(crate) fn new(method: impl AsRef<str>, url: impl AsRef<str>) -> Request {
91-
Request::new(method, url)
92-
}
9392
9493
/// An HTTP Fetch Request.
9594
pub(crate) struct Request {
9695
init: RequestInit,
9796
url: String,
97+
_body_buf: Pin<Vec<u8>>,
9898
}
9999

100100
impl Request {
101101
/// Create a new instance.
102-
pub(crate) fn new(method: impl AsRef<str>, url: impl AsRef<str>) -> Self {
102+
pub(crate) fn new(req: super::Request) -> Result<Self, io::Error> {
103+
let (
104+
Parts {
105+
method,
106+
uri,
107+
headers,
108+
..
109+
},
110+
mut body,
111+
) = req.into_parts();
112+
113+
//create a fetch request initaliser
103114
let mut init = web_sys::RequestInit::new();
115+
116+
//set the fetch method
104117
init.method(method.as_ref());
105-
Self {
106-
init,
107-
url: url.as_ref().to_owned(),
118+
119+
//add any fetch headers
120+
let init_headers = web_sys::Headers::new().unwrap();
121+
for (name, value) in headers.iter() {
122+
init_headers
123+
.append(name.as_str(), value.to_str().unwrap())
124+
.map_err(|_| {
125+
io::Error::new(
126+
io::ErrorKind::Other,
127+
format!(
128+
"could not add header: {} = {}",
129+
name.as_str(),
130+
value.to_str().expect("could not stringify header value")
131+
),
132+
)
133+
})?;
134+
}
135+
init.headers(&init_headers);
136+
137+
//convert the body into a uint8 array
138+
// needs to be pinned and retained inside the Request because the Uint8Array passed to
139+
// js is just a portal into WASM linear memory, and if the underlying data is moved the
140+
// js ref will become silently invalid
141+
let mut body_buf = Vec::with_capacity(1024);
142+
futures::executor::block_on(body.read_to_end(&mut body_buf)).map_err(|_| {
143+
io::Error::new(io::ErrorKind::Other, "could not read body into a buffer")
144+
})?;
145+
let body_pinned = Pin::new(body_buf);
146+
if body_pinned.len() > 0 {
147+
unsafe {
148+
let uint_8_array = js_sys::Uint8Array::view(&body_pinned);
149+
init.body(Some(&uint_8_array));
150+
}
108151
}
152+
153+
Ok(Self {
154+
init,
155+
url: uri.to_string(),
156+
_body_buf: body_pinned,
157+
})
109158
}
110159

111160
/// Submit a request

0 commit comments

Comments
 (0)