wasm: Add request body in the form of Bytes (#696)

* Add body bytes

* Add example and header creation code
This commit is contained in:
John Gallagher
2019-11-04 12:17:05 -05:00
committed by Sean McArthur
parent b24b0be461
commit f6f81f9cc1
11 changed files with 6306 additions and 9 deletions

View File

@@ -1,3 +1,59 @@
/// dox
#[derive(Debug)]
pub struct Body(());
use bytes::Bytes;
use std::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
pub struct Body(Bytes);
impl Body {
pub(crate) fn bytes(&self) -> &Bytes {
&self.0
}
}
impl From<Bytes> for Body {
#[inline]
fn from(bytes: Bytes) -> Body {
Body(bytes)
}
}
impl From<Vec<u8>> for Body {
#[inline]
fn from(vec: Vec<u8>) -> Body {
Body(vec.into())
}
}
impl From<&'static [u8]> for Body {
#[inline]
fn from(s: &'static [u8]) -> Body {
Body(Bytes::from_static(s))
}
}
impl From<String> for Body {
#[inline]
fn from(s: String) -> Body {
Body(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()
}
}

View File

@@ -1,9 +1,10 @@
use std::future::Future;
use http::Method;
use js_sys::Uint8Array;
use std::future::Future;
use wasm_bindgen::UnwrapThrowExt as _;
use crate::IntoUrl;
use super::{Request, RequestBuilder, Response};
use crate::IntoUrl;
/// dox
#[derive(Clone, Debug)]
@@ -91,7 +92,10 @@ impl Client {
RequestBuilder::new(self.clone(), req)
}
pub(super) fn execute_request(&self, req: Request) -> impl Future<Output = crate::Result<Response>> {
pub(super) fn execute_request(
&self,
req: Request,
) -> impl Future<Output = crate::Result<Response>> {
fetch(req)
}
}
@@ -107,12 +111,21 @@ async fn fetch(req: Request) -> crate::Result<Response> {
for (name, value) in req.headers() {
js_headers
.append(name.as_str(), value.to_str().map_err(crate::error::builder)?)
.append(
name.as_str(),
value.to_str().map_err(crate::error::builder)?,
)
.map_err(crate::error::wasm)
.map_err(crate::error::builder)?;
}
init.headers(&js_headers.into());
if let Some(body) = req.body() {
let body_bytes: &[u8] = body.bytes();
let body_array: Uint8Array = body_bytes.into();
init.body(Some(&body_array.into()));
}
let js_req = web_sys::Request::new_with_str_and_init(req.url().as_str(), &init)
.map_err(crate::error::wasm)
.map_err(crate::error::builder)?;
@@ -160,5 +173,4 @@ impl ClientBuilder {
pub fn build(self) -> Result<Client, crate::Error> {
Ok(Client(()))
}
}

View File

@@ -1,9 +1,11 @@
use http::HttpTryFrom;
use std::fmt;
use http::{Method, HeaderMap};
use http::Method;
use url::Url;
use super::{Body, Client, Response};
use crate::header::{HeaderMap, HeaderName, HeaderValue};
/// A request which can be executed with `Client::execute()`.
pub struct Request {
@@ -83,7 +85,6 @@ impl RequestBuilder {
RequestBuilder { client, request }
}
/// Set the request body.
pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
if let Ok(ref mut req) = self.request {
@@ -92,6 +93,30 @@ impl RequestBuilder {
self
}
/// Add a `Header` to this Request.
pub fn header<K, V>(mut self, key: K, value: V) -> RequestBuilder
where
HeaderName: HttpTryFrom<K>,
HeaderValue: HttpTryFrom<V>,
{
let mut error = None;
if let Ok(ref mut req) = self.request {
match <HeaderName as HttpTryFrom<K>>::try_from(key) {
Ok(key) => match <HeaderValue as HttpTryFrom<V>>::try_from(value) {
Ok(value) => {
req.headers_mut().append(key, value);
}
Err(e) => error = Some(crate::error::builder(e.into())),
},
Err(e) => error = Some(crate::error::builder(e.into())),
};
}
if let Some(err) = error {
self.request = Err(err);
}
self
}
/// Constructs the Request and sends it to the target URL, returning a
/// future Response.
///