Skip to content

Commit

Permalink
refactor(wasm): remove extra component implementations
Browse files Browse the repository at this point in the history
Signed-off-by: Brooks Townsend <[email protected]>
  • Loading branch information
brooksmtownsend committed Aug 21, 2024
1 parent ee51e28 commit 3ef4eb4
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 755 deletions.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,6 @@ if_wasm! {
mod util;

pub use self::wasm::{Body, Client, ClientBuilder, Request, RequestBuilder, Response};
#[cfg(feature = "multipart")]
#[cfg(all(not(all(target_os = "wasi", target_env = "p2")), feature = "multipart"))]
pub use self::wasm::multipart;
}
174 changes: 1 addition & 173 deletions src/wasm/component/body.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,13 @@
#[cfg(feature = "multipart")]
use super::multipart::Form;
/// dox
use bytes::Bytes;
use std::{borrow::Cow, fmt};

/// The body of a `Request`.
///
/// In most cases, this is not needed directly, as the
/// [`RequestBuilder.body`][builder] method uses `Into<Body>`, which allows
/// passing many things (like a string or vector of bytes).
///
/// [builder]: ./struct.RequestBuilder.html#method.body
/// The body of a [`super::Request`].
pub struct Body {
inner: Inner,
}

enum Inner {
Single(Single),
/// MultipartForm holds a multipart/form-data body.
#[cfg(feature = "multipart")]
MultipartForm(Form),
}

#[derive(Clone)]
Expand Down Expand Up @@ -52,46 +40,13 @@ impl Body {
pub fn as_bytes(&self) -> Option<&[u8]> {
match &self.inner {
Inner::Single(single) => Some(single.as_bytes()),
#[cfg(feature = "multipart")]
Inner::MultipartForm(_) => None,
}
}

#[cfg(feature = "multipart")]
pub(crate) fn as_single(&self) -> Option<&Single> {
match &self.inner {
Inner::Single(single) => Some(single),
Inner::MultipartForm(_) => None,
}
}

#[inline]
#[cfg(feature = "multipart")]
pub(crate) fn from_form(f: Form) -> Body {
Self {
inner: Inner::MultipartForm(f),
}
}

/// into_part turns a regular body into the body of a multipart/form-data part.
#[cfg(feature = "multipart")]
pub(crate) fn into_part(self) -> Body {
match self.inner {
Inner::Single(single) => Self {
inner: Inner::Single(single),
},
Inner::MultipartForm(form) => Self {
inner: Inner::MultipartForm(form),
},
}
}

#[allow(unused)]
pub(crate) fn is_empty(&self) -> bool {
match &self.inner {
Inner::Single(single) => single.is_empty(),
#[cfg(feature = "multipart")]
Inner::MultipartForm(form) => form.is_empty(),
}
}

Expand All @@ -100,8 +55,6 @@ impl Body {
Inner::Single(single) => Some(Self {
inner: Inner::Single(single.clone()),
}),
#[cfg(feature = "multipart")]
Inner::MultipartForm(_) => None,
}
}
}
Expand Down Expand Up @@ -156,128 +109,3 @@ impl fmt::Debug for Body {
f.debug_struct("Body").finish()
}
}

#[cfg(test)]
mod tests {
// use crate::Body;
// use js_sys::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() {
// let body = Body::from("TEST");
// assert_eq!([84, 69, 83, 84], body.as_bytes().unwrap());
// }

// #[wasm_bindgen_test]
// async fn test_body_js_static_str() {
// 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::<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_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);
// }
}
11 changes: 5 additions & 6 deletions src/wasm/component/client/future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ use std::{
};

use futures_core::Future;
use wasi::{
self,
http::{
outgoing_handler::{FutureIncomingResponse, OutgoingRequest},
types::{OutgoingBody, OutputStream},
},
use wasi::http::{
outgoing_handler::{FutureIncomingResponse, OutgoingRequest},
types::{OutgoingBody, OutputStream},
};

use crate::{Body, Request, Response};

/// A [`Future`] implementation for a [`Response`] that uses the [`wasi::io::poll`]
/// primitives to poll receipt of the HTTP response.
#[derive(Debug)]
pub struct ResponseFuture {
request: Request,
Expand Down
75 changes: 16 additions & 59 deletions src/wasm/component/client.rs → src/wasm/component/client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,41 +1,40 @@
#![allow(warnings)]

use http::header::{CONTENT_LENGTH, USER_AGENT};
use http::header::{Entry, CONTENT_LENGTH, USER_AGENT};
use http::{HeaderMap, HeaderValue, Method};
use std::any::Any;
use std::convert::TryInto;
use std::pin::Pin;
use std::task::{ready, Context, Poll};
use std::{fmt, future::Future, sync::Arc};

use self::future::ResponseFuture;

use super::{Request, RequestBuilder, Response};
use crate::Body;
use crate::IntoUrl;
use wasi::http::outgoing_handler::{self, OutgoingRequest};
use crate::wasm::component::{Request, RequestBuilder, Response};
use crate::{Body, IntoUrl};
use wasi::http::outgoing_handler::OutgoingRequest;
use wasi::http::types::{FutureIncomingResponse, OutgoingBody, OutputStream, Pollable};

mod future;
use future::ResponseFuture;

/// dox
#[derive(Clone)]
/// A client for making HTTP requests.
#[derive(Default, Debug, Clone)]
pub struct Client {
config: Arc<Config>,
}

/// dox
/// A builder to configure a [`Client`].
#[derive(Default, Debug)]
pub struct ClientBuilder {
config: Config,
}

impl Client {
/// Constructs a new `Client`.
/// Constructs a new [`Client`].
pub fn new() -> Self {
Client::builder().build().expect("Client::new()")
}

/// dox
/// Constructs a new [`ClientBuilder`].
pub fn builder() -> ClientBuilder {
ClientBuilder::new()
}
Expand Down Expand Up @@ -123,12 +122,10 @@ impl Client {
self.execute_request(request)
}

// merge request headers with Client default_headers, prior to external http fetch
fn merge_headers(&self, req: &mut Request) {
use http::header::Entry;
/// Merge [`Request`] headers with default headers set in [`Config`]
fn merge_default_headers(&self, req: &mut Request) {
let headers: &mut HeaderMap = req.headers_mut();
// insert default headers in the request headers
// without overwriting already appended headers.
// Insert without overwriting existing headers
for (key, value) in self.config.headers.iter() {
if let Entry::Vacant(entry) = headers.entry(key) {
entry.insert(value.clone());
Expand All @@ -137,37 +134,14 @@ impl Client {
}

pub(super) fn execute_request(&self, mut req: Request) -> crate::Result<ResponseFuture> {
self.merge_headers(&mut req);
self.merge_default_headers(&mut req);
fetch(req)
}
}

impl Default for Client {
fn default() -> Self {
Self::new()
}
}

impl fmt::Debug for Client {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut builder = f.debug_struct("Client");
self.config.fmt_fields(&mut builder);
builder.finish()
}
}

impl fmt::Debug for ClientBuilder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut builder = f.debug_struct("ClientBuilder");
self.config.fmt_fields(&mut builder);
builder.finish()
}
}

fn fetch(req: Request) -> crate::Result<ResponseFuture> {
let headers = wasi::http::types::Fields::new();
for (name, value) in req.headers() {
// TODO: see if we can avoid the extra allocation
headers
.append(&name.to_string(), &value.as_bytes().to_vec())
.map_err(crate::error::builder)?;
Expand Down Expand Up @@ -232,8 +206,6 @@ fn fetch(req: Request) -> crate::Result<ResponseFuture> {
ResponseFuture::new(req, outgoing_request)
}

// ===== impl ClientBuilder =====

impl ClientBuilder {
/// Return a new `ClientBuilder`.
pub fn new() -> Self {
Expand Down Expand Up @@ -280,27 +252,12 @@ impl ClientBuilder {
}
}

impl Default for ClientBuilder {
fn default() -> Self {
Self::new()
}
}

#[derive(Debug)]
#[derive(Default, Debug)]
struct Config {
headers: HeaderMap,
error: Option<crate::Error>,
}

impl Default for Config {
fn default() -> Config {
Config {
headers: HeaderMap::new(),
error: None,
}
}
}

impl Config {
fn fmt_fields(&self, f: &mut fmt::DebugStruct<'_, '_>) {
f.field("default_headers", &self.headers);
Expand Down
2 changes: 0 additions & 2 deletions src/wasm/component/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
mod body;
mod client;
#[cfg(feature = "multipart")]
pub mod multipart;
mod request;
mod response;

Expand Down
Loading

0 comments on commit 3ef4eb4

Please sign in to comment.