diff --git a/src/wasm/component/client.rs b/src/wasm/component/client.rs index ed54d4630..8347c2c34 100644 --- a/src/wasm/component/client.rs +++ b/src/wasm/component/client.rs @@ -1,6 +1,6 @@ #![allow(warnings)] -use http::header::USER_AGENT; +use http::header::{CONTENT_LENGTH, USER_AGENT}; use http::{HeaderMap, HeaderValue, Method}; use std::any::Any; use std::convert::TryInto; @@ -175,17 +175,29 @@ fn fetch(req: Request) -> crate::Result { .map_err(crate::error::builder)?; } + if let Some(body) = req.body().and_then(|b| b.as_bytes()) { + headers + .append( + &CONTENT_LENGTH.to_string(), + &format!("{}", body.len()).as_bytes().to_vec(), + ) + .map_err(crate::error::builder)?; + } + // Construct `OutgoingRequest` let outgoing_request = wasi::http::types::OutgoingRequest::new(headers); let url = req.url(); + if url.has_authority() { outgoing_request .set_authority(Some(url.authority())) .map_err(|_| crate::error::request("failed to set authority on request"))?; } + outgoing_request .set_path_with_query(Some(url.path())) .map_err(|_| crate::error::request("failed to set path with query on request"))?; + match url.scheme() { "http" => outgoing_request.set_scheme(Some(&wasi::http::types::Scheme::Http)), "https" => outgoing_request.set_scheme(Some(&wasi::http::types::Scheme::Https)), diff --git a/src/wasm/component/client/future.rs b/src/wasm/component/client/future.rs index 753fb2eb6..ec5a5da46 100644 --- a/src/wasm/component/client/future.rs +++ b/src/wasm/component/client/future.rs @@ -34,13 +34,16 @@ impl ResponseFuture { return Err(crate::error::request("outgoing body write error")); }; - RequestState::Write(RequestWriteState { - outgoing_request: Some(outgoing_request), - outgoing_body: Some(outgoing_body), - stream: Some(stream), - body, - bytes_written: 0, - }) + match wasi::http::outgoing_handler::handle(outgoing_request, None) { + Ok(future) => RequestState::Write(RequestWriteState { + response_future: Some(future), + outgoing_body: Some(outgoing_body), + stream: Some(stream), + body, + bytes_written: 0, + }), + Err(e) => return Err(crate::error::request("request error")), + } } None => match wasi::http::outgoing_handler::handle(outgoing_request, None) { Ok(future) => RequestState::Response(future), @@ -101,7 +104,7 @@ enum RequestState { #[derive(Debug)] struct RequestWriteState { - outgoing_request: Option, + response_future: Option, outgoing_body: Option, stream: Option, body: Body, @@ -126,31 +129,35 @@ impl Future for RequestWriteState { // stream is ready when all data is flushed, and if we wrote all the bytes we // are ready to continue. if this.bytes_written == bytes.len() as u64 { + if stream.flush().is_err() { + return Poll::Ready(Err(crate::error::request( + "outgoing body write flush error", + ))); + } + if stream.subscribe().ready() { // will trap if not dropped before body drop(stream); - let outgoing_request = this.outgoing_request.take().expect("state error"); + let future = this.response_future.take().expect("state error"); let outgoing_body = this.outgoing_body.take().expect("state error"); if OutgoingBody::finish(outgoing_body, None).is_err() { return Poll::Ready(Err(crate::error::request("request error"))); } - match wasi::http::outgoing_handler::handle(outgoing_request, None) { - Ok(future) => { - return Poll::Ready(Ok(future)); - } - Err(e) => { - return Poll::Ready(Err(crate::error::request("request error"))); - } - } + return Poll::Ready(Ok(future)); } else { this.stream.insert(stream); cx.waker().wake_by_ref(); return Poll::Pending; } + } else if !stream.subscribe().ready() { + this.stream.insert(stream); + cx.waker().wake_by_ref(); + + return Poll::Pending; } let Ok(bytes_to_write) = stream @@ -171,12 +178,6 @@ impl Future for RequestWriteState { ))); }; - if stream.flush().is_err() { - return Poll::Ready(Err(crate::error::request( - "outgoing body write flush error", - ))); - } - this.bytes_written += bytes_to_write; this.stream.insert(stream); diff --git a/src/wasm/component/request.rs b/src/wasm/component/request.rs index d122fdae0..038caa056 100644 --- a/src/wasm/component/request.rs +++ b/src/wasm/component/request.rs @@ -10,7 +10,7 @@ use url::Url; use web_sys::RequestCredentials; use super::{Body, Client, Response}; -use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE}; +use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_LENGTH, CONTENT_TYPE}; /// A request which can be executed with `Client::execute()`. pub struct Request {