Introduce unstable, incomplete WASM support
This commit is contained in:
		| @@ -47,10 +47,18 @@ matrix: | ||||
|         #- rust: nightly | ||||
|         #  env: FEATURES="--features socks" | ||||
|  | ||||
|         # trust-dns | ||||
|         #- rust: stable | ||||
|         #- rust: nightly | ||||
|         #  env: FEATURES="--features trust-dns" | ||||
|  | ||||
|         # wasm | ||||
|         - name: "WASM" | ||||
|           env: TARGET=wasm32-unknown-unknown | ||||
|           rust: nightly | ||||
|           install: rustup target add "$TARGET" | ||||
|           script: cargo check --target "$TARGET" | ||||
|  | ||||
|         # android | ||||
|         #- rust: stable | ||||
|         - rust: nightly | ||||
|   | ||||
							
								
								
									
										63
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								Cargo.toml
									
									
									
									
									
								
							| @@ -17,13 +17,34 @@ publish = false | ||||
| [package.metadata.docs.rs] | ||||
| all-features = true | ||||
|  | ||||
| [features] | ||||
| default = ["default-tls"] | ||||
|  | ||||
| tls = [] | ||||
|  | ||||
| default-tls = ["hyper-tls", "native-tls", "tls", "tokio-tls"] | ||||
| default-tls-vendored = ["default-tls", "native-tls/vendored"] | ||||
|  | ||||
| #rustls-tls = ["hyper-rustls", "tokio-rustls", "webpki-roots", "rustls", "tls"] | ||||
|  | ||||
| blocking = ["futures-channel-preview", "futures-util-preview/io"] | ||||
|  | ||||
| cookies = ["cookie_crate", "cookie_store"] | ||||
|  | ||||
| gzip = ["async-compression"] | ||||
|  | ||||
| #trust-dns = ["trust-dns-resolver"] | ||||
|  | ||||
| [dependencies] | ||||
| http = "0.1.15" | ||||
| url = "2.1" | ||||
|  | ||||
| [target.'cfg(not(target_arch = "wasm32"))'.dependencies] | ||||
| base64 = "0.10" | ||||
| bytes = "0.4" | ||||
| encoding_rs = "0.8" | ||||
| futures-core-preview = { version = "=0.3.0-alpha.18" } | ||||
| futures-util-preview = { version = "=0.3.0-alpha.18" } | ||||
| http = "0.1.15" | ||||
| http-body = "=0.2.0-alpha.1" | ||||
| hyper = "=0.13.0-alpha.2" | ||||
| log = "0.4" | ||||
| @@ -32,13 +53,11 @@ mime_guess = "2.0" | ||||
| percent-encoding = "2.1" | ||||
| tokio = { version = "=0.2.0-alpha.5", default-features = false, features = ["rt-full", "tcp"] } | ||||
| tokio-executor = "=0.2.0-alpha.5" | ||||
| url = "2.1" | ||||
| uuid = { version = "0.7", features = ["v4"] } | ||||
| time = "0.1.42" | ||||
|  | ||||
| # TODO: candidates for optional features | ||||
|  | ||||
|  | ||||
| serde = "1.0" | ||||
| serde_json = "1.0" | ||||
| serde_urlencoded = "0.6.1" | ||||
| @@ -72,7 +91,7 @@ async-compression = { version = "0.1.0-alpha.4", default-features = false, featu | ||||
| ## trust-dns | ||||
| #trust-dns-resolver = { version = "0.11", optional = true } | ||||
|  | ||||
| [dev-dependencies] | ||||
| [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] | ||||
| env_logger = "0.6" | ||||
| hyper = { version = "=0.13.0-alpha.2", features = ["unstable-stream"] } | ||||
| serde = { version = "1.0", features = ["derive"] } | ||||
| @@ -80,28 +99,26 @@ libflate = "0.1" | ||||
| doc-comment = "0.3" | ||||
| tokio-fs = { version = "=0.2.0-alpha.5" } | ||||
|  | ||||
| [features] | ||||
| default = ["default-tls"] | ||||
|  | ||||
| tls = [] | ||||
|  | ||||
| default-tls = ["hyper-tls", "native-tls", "tls", "tokio-tls"] | ||||
| default-tls-vendored = ["default-tls", "native-tls/vendored"] | ||||
|  | ||||
| # re-enable CI also | ||||
| #rustls-tls = ["hyper-rustls", "tokio-rustls", "webpki-roots", "rustls", "tls"] | ||||
|  | ||||
| blocking = ["futures-channel-preview", "futures-util-preview/io"] | ||||
|  | ||||
| cookies = ["cookie_crate", "cookie_store"] | ||||
|  | ||||
| gzip = ["async-compression"] | ||||
|  | ||||
| #trust-dns = ["trust-dns-resolver"] | ||||
|  | ||||
| [target.'cfg(windows)'.dependencies] | ||||
| winreg = "0.6" | ||||
|  | ||||
| # wasm | ||||
|  | ||||
| [target.'cfg(target_arch = "wasm32")'.dependencies] | ||||
| js-sys = "0.3.25" | ||||
| wasm-bindgen = "0.2.48" | ||||
| wasm-bindgen-futures = { version = "", features = ["futures_0_3"] } | ||||
|  | ||||
| [target.'cfg(target_arch = "wasm32")'.dependencies.web-sys] | ||||
| version = "0.3.25" | ||||
| features = [ | ||||
|     "Headers", | ||||
|     "Request", | ||||
|     "RequestInit", | ||||
|     "Response", | ||||
|     "Window", | ||||
| ] | ||||
|  | ||||
| [[example]] | ||||
| name = "blocking" | ||||
| path = "examples/blocking.rs" | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| #![cfg_attr(target_arch = "wasm32", allow(unused))] | ||||
| use std::error::Error as StdError; | ||||
| use std::fmt; | ||||
| use std::io; | ||||
| @@ -12,7 +13,7 @@ pub struct Error { | ||||
|     inner: Box<Inner>, | ||||
| } | ||||
|  | ||||
| type BoxError = Box<dyn StdError + Send + Sync>; | ||||
| pub(crate) type BoxError = Box<dyn StdError + Send + Sync>; | ||||
|  | ||||
| struct Inner { | ||||
|     kind: Kind, | ||||
| @@ -213,6 +214,12 @@ pub(crate) fn url_bad_scheme(url: Url) -> Error { | ||||
|     Error::new(Kind::Builder, Some("URL scheme is not allowed")).with_url(url) | ||||
| } | ||||
|  | ||||
| if_wasm! { | ||||
|     pub(crate) fn wasm(js_val: wasm_bindgen::JsValue) -> BoxError { | ||||
|         format!("{:?}", js_val).into() | ||||
|     } | ||||
| } | ||||
|  | ||||
| // io::Error helpers | ||||
|  | ||||
| #[allow(unused)] | ||||
|   | ||||
| @@ -37,14 +37,16 @@ impl<'a> PolyfillTryInto for &'a String { | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub(crate) fn expect_uri(url: &Url) -> hyper::Uri { | ||||
|     url.as_str() | ||||
|         .parse() | ||||
|         .expect("a parsed Url should always be a valid Uri") | ||||
| } | ||||
| if_hyper! { | ||||
|     pub(crate) fn expect_uri(url: &Url) -> http::Uri { | ||||
|         url.as_str() | ||||
|             .parse() | ||||
|             .expect("a parsed Url should always be a valid Uri") | ||||
|     } | ||||
|  | ||||
| pub(crate) fn try_uri(url: &Url) -> Option<hyper::Uri> { | ||||
|     url.as_str().parse().ok() | ||||
|     pub(crate) fn try_uri(url: &Url) -> Option<http::Uri> { | ||||
|         url.as_str().parse().ok() | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
|   | ||||
							
								
								
									
										114
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										114
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -175,60 +175,32 @@ | ||||
| ////! - **trust-dns**: Enables a trust-dns async resolver instead of default | ||||
| ////!   threadpool using `getaddrinfo`. | ||||
|  | ||||
| #[cfg(test)] | ||||
| #[macro_use] | ||||
| extern crate doc_comment; | ||||
| macro_rules! if_wasm { | ||||
|     ($($item:item)*) => {$( | ||||
|         #[cfg(target_arch = "wasm32")] | ||||
|         $item | ||||
|     )*} | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| doctest!("../README.md"); | ||||
| macro_rules! if_hyper { | ||||
|     ($($item:item)*) => {$( | ||||
|         #[cfg(not(target_arch = "wasm32"))] | ||||
|         $item | ||||
|     )*} | ||||
| } | ||||
|  | ||||
| pub use hyper::header; | ||||
| pub use hyper::Method; | ||||
| pub use hyper::{StatusCode, Version}; | ||||
| pub use url::ParseError as UrlError; | ||||
| pub use http::header; | ||||
| pub use http::Method; | ||||
| pub use http::{StatusCode, Version}; | ||||
| pub use url::Url; | ||||
|  | ||||
| pub use self::async_impl::{ | ||||
|     multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response, | ||||
| }; | ||||
| //pub use self::body::Body; | ||||
| //pub use self::client::{Client, ClientBuilder}; | ||||
| pub use self::error::{Error, Result}; | ||||
| pub use self::into_url::IntoUrl; | ||||
| pub use self::proxy::Proxy; | ||||
| pub use self::redirect::{RedirectAction, RedirectAttempt, RedirectPolicy}; | ||||
| //pub use self::request::{Request, RequestBuilder}; | ||||
| //pub use self::response::Response; | ||||
| #[cfg(feature = "tls")] | ||||
| pub use self::tls::{Certificate, Identity}; | ||||
|  | ||||
| // this module must be first because of the `try_` macro | ||||
| // universal mods | ||||
| #[macro_use] | ||||
| mod error; | ||||
|  | ||||
| mod async_impl; | ||||
| #[cfg(feature = "blocking")] | ||||
| pub mod blocking; | ||||
| mod connect; | ||||
| #[cfg(feature = "cookies")] | ||||
| pub mod cookie; | ||||
| //#[cfg(feature = "trust-dns")] | ||||
| //mod dns; | ||||
| mod into_url; | ||||
| mod proxy; | ||||
| mod redirect; | ||||
| #[cfg(feature = "tls")] | ||||
| mod tls; | ||||
|  | ||||
| //pub mod multipart; | ||||
|  | ||||
| #[doc(hidden)] | ||||
| #[deprecated(note = "types moved to top of crate")] | ||||
| pub mod r#async { | ||||
|     pub use crate::async_impl::{ | ||||
|         multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response, | ||||
|     }; | ||||
| } | ||||
| pub use self::error::{Error, Result}; | ||||
| pub use self::into_url::IntoUrl; | ||||
|  | ||||
| /// Shortcut method to quickly make a `GET` request. | ||||
| /// | ||||
| @@ -274,8 +246,56 @@ fn _assert_impls() { | ||||
|     assert_send::<Request>(); | ||||
|     assert_send::<RequestBuilder>(); | ||||
|  | ||||
|     assert_send::<Response>(); | ||||
|     #[cfg(not(target_arch = "wasm32"))] | ||||
|     { | ||||
|         assert_send::<Response>(); | ||||
|     } | ||||
|  | ||||
|     assert_send::<Error>(); | ||||
|     assert_sync::<Error>(); | ||||
| } | ||||
|  | ||||
| if_hyper! { | ||||
|     #[cfg(test)] | ||||
|     #[macro_use] | ||||
|     extern crate doc_comment; | ||||
|  | ||||
|     #[cfg(test)] | ||||
|     doctest!("../README.md"); | ||||
|  | ||||
|     pub use self::async_impl::{ | ||||
|         multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response, | ||||
|     }; | ||||
|     pub use self::proxy::Proxy; | ||||
|     pub use self::redirect::{RedirectAction, RedirectAttempt, RedirectPolicy}; | ||||
|     #[cfg(feature = "tls")] | ||||
|     pub use self::tls::{Certificate, Identity}; | ||||
|  | ||||
|  | ||||
|     mod async_impl; | ||||
|     #[cfg(feature = "blocking")] | ||||
|     pub mod blocking; | ||||
|     mod connect; | ||||
|     #[cfg(feature = "cookies")] | ||||
|     pub mod cookie; | ||||
|     //#[cfg(feature = "trust-dns")] | ||||
|     //mod dns; | ||||
|     mod proxy; | ||||
|     mod redirect; | ||||
|     #[cfg(feature = "tls")] | ||||
|     mod tls; | ||||
|  | ||||
|     #[doc(hidden)] | ||||
|     #[deprecated(note = "types moved to top of crate")] | ||||
|     pub mod r#async { | ||||
|         pub use crate::async_impl::{ | ||||
|             multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response, | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|  | ||||
| if_wasm! { | ||||
|     mod wasm; | ||||
|  | ||||
|     pub use self::wasm::{Body, Client, ClientBuilder, Request, RequestBuilder, Response}; | ||||
| } | ||||
|   | ||||
							
								
								
									
										3
									
								
								src/wasm/body.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/wasm/body.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| /// dox | ||||
| #[derive(Debug)] | ||||
| pub struct Body(()); | ||||
							
								
								
									
										162
									
								
								src/wasm/client.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								src/wasm/client.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | ||||
| use std::future::Future; | ||||
| use http::Method; | ||||
| use wasm_bindgen::UnwrapThrowExt as _; | ||||
|  | ||||
| use crate::IntoUrl; | ||||
| use super::{Request, RequestBuilder, Response}; | ||||
|  | ||||
| /// dox | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct Client(()); | ||||
|  | ||||
| /// dox | ||||
| #[derive(Debug)] | ||||
| pub struct ClientBuilder(()); | ||||
|  | ||||
| impl Client { | ||||
|     /// dox | ||||
|     pub fn new() -> Self { | ||||
|         Client::builder().build().unwrap_throw() | ||||
|     } | ||||
|  | ||||
|     /// dox | ||||
|     pub fn builder() -> ClientBuilder { | ||||
|         ClientBuilder::new() | ||||
|     } | ||||
|  | ||||
|     /// Convenience method to make a `GET` request to a URL. | ||||
|     /// | ||||
|     /// # Errors | ||||
|     /// | ||||
|     /// This method fails whenever supplied `Url` cannot be parsed. | ||||
|     pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder { | ||||
|         self.request(Method::GET, url) | ||||
|     } | ||||
|  | ||||
|     /// Convenience method to make a `POST` request to a URL. | ||||
|     /// | ||||
|     /// # Errors | ||||
|     /// | ||||
|     /// This method fails whenever supplied `Url` cannot be parsed. | ||||
|     pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder { | ||||
|         self.request(Method::POST, url) | ||||
|     } | ||||
|  | ||||
|     /// Convenience method to make a `PUT` request to a URL. | ||||
|     /// | ||||
|     /// # Errors | ||||
|     /// | ||||
|     /// This method fails whenever supplied `Url` cannot be parsed. | ||||
|     pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder { | ||||
|         self.request(Method::PUT, url) | ||||
|     } | ||||
|  | ||||
|     /// Convenience method to make a `PATCH` request to a URL. | ||||
|     /// | ||||
|     /// # Errors | ||||
|     /// | ||||
|     /// This method fails whenever supplied `Url` cannot be parsed. | ||||
|     pub fn patch<U: IntoUrl>(&self, url: U) -> RequestBuilder { | ||||
|         self.request(Method::PATCH, url) | ||||
|     } | ||||
|  | ||||
|     /// Convenience method to make a `DELETE` request to a URL. | ||||
|     /// | ||||
|     /// # Errors | ||||
|     /// | ||||
|     /// This method fails whenever supplied `Url` cannot be parsed. | ||||
|     pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder { | ||||
|         self.request(Method::DELETE, url) | ||||
|     } | ||||
|  | ||||
|     /// Convenience method to make a `HEAD` request to a URL. | ||||
|     /// | ||||
|     /// # Errors | ||||
|     /// | ||||
|     /// This method fails whenever supplied `Url` cannot be parsed. | ||||
|     pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder { | ||||
|         self.request(Method::HEAD, url) | ||||
|     } | ||||
|  | ||||
|     /// Start building a `Request` with the `Method` and `Url`. | ||||
|     /// | ||||
|     /// Returns a `RequestBuilder`, which will allow setting headers and | ||||
|     /// request body before sending. | ||||
|     /// | ||||
|     /// # Errors | ||||
|     /// | ||||
|     /// This method fails whenever supplied `Url` cannot be parsed. | ||||
|     pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder { | ||||
|         let req = url.into_url().map(move |url| Request::new(method, url)); | ||||
|         RequestBuilder::new(self.clone(), req) | ||||
|     } | ||||
|  | ||||
|     pub(super) fn execute_request(&self, req: Request) -> impl Future<Output = crate::Result<Response>> { | ||||
|         fetch(req) | ||||
|     } | ||||
| } | ||||
|  | ||||
| async fn fetch(req: Request) -> crate::Result<Response> { | ||||
|     // Build the js Request | ||||
|     let mut init = web_sys::RequestInit::new(); | ||||
|     init.method(req.method().as_str()); | ||||
|  | ||||
|     let js_headers = web_sys::Headers::new() | ||||
|         .map_err(crate::error::wasm) | ||||
|         .map_err(crate::error::builder)?; | ||||
|  | ||||
|     for (name, value) in req.headers() { | ||||
|         js_headers | ||||
|             .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()); | ||||
|  | ||||
|     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)?; | ||||
|  | ||||
|     // Await the fetch() promise | ||||
|     let p = web_sys::window() | ||||
|         .expect("window should exist") | ||||
|         .fetch_with_request(&js_req); | ||||
|     let js_resp = super::promise::<web_sys::Response>(p) | ||||
|         .await | ||||
|         .map_err(crate::error::request)?; | ||||
|  | ||||
|     // Convert from the js Response | ||||
|     let mut resp = http::Response::builder(); | ||||
|     resp.status(js_resp.status()); | ||||
|  | ||||
|     // TODO: translate js_resp.headers() | ||||
|     /* | ||||
|     let js_headers = js_resp.headers(); | ||||
|     let js_iter = js_sys::try_iter(&js_headers) | ||||
|         .expect_throw("headers try_iter") | ||||
|         .expect_throw("headers have an iterator"); | ||||
|  | ||||
|     for item in js_iter { | ||||
|         let item = item.expect_throw("headers iterator doesn't throw"); | ||||
|     } | ||||
|     */ | ||||
|  | ||||
|     resp.body(js_resp) | ||||
|         .map(Response::new) | ||||
|         .map_err(crate::error::request) | ||||
| } | ||||
|  | ||||
| // ===== impl ClientBuilder ===== | ||||
|  | ||||
| impl ClientBuilder { | ||||
|     /// dox | ||||
|     pub fn new() -> Self { | ||||
|         ClientBuilder(()) | ||||
|     } | ||||
|  | ||||
|     /// dox | ||||
|     pub fn build(self) -> Result<Client, crate::Error> { | ||||
|         Ok(Client(())) | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										29
									
								
								src/wasm/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/wasm/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| use wasm_bindgen::JsCast; | ||||
|  | ||||
| mod body; | ||||
| mod client; | ||||
| mod request; | ||||
| mod response; | ||||
|  | ||||
| pub use self::body::Body; | ||||
| pub use self::client::{Client, ClientBuilder}; | ||||
| pub use self::request::{Request, RequestBuilder}; | ||||
| pub use self::response::Response; | ||||
|  | ||||
|  | ||||
| async fn promise<T>(promise: js_sys::Promise) -> Result<T, crate::error::BoxError> | ||||
| where | ||||
|     T: JsCast, | ||||
| { | ||||
|     use wasm_bindgen_futures::futures_0_3::JsFuture; | ||||
|  | ||||
|     let js_val = JsFuture::from(promise) | ||||
|         .await | ||||
|         .map_err(crate::error::wasm)?; | ||||
|  | ||||
|     js_val | ||||
|         .dyn_into::<T>() | ||||
|         .map_err(|_js_val| { | ||||
|             "promise resolved to unexpected type".into() | ||||
|         }) | ||||
| } | ||||
							
								
								
									
										144
									
								
								src/wasm/request.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								src/wasm/request.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | ||||
| use std::fmt; | ||||
|  | ||||
| use http::{Method, HeaderMap}; | ||||
| use url::Url; | ||||
|  | ||||
| use super::{Body, Client, Response}; | ||||
|  | ||||
| /// A request which can be executed with `Client::execute()`. | ||||
| pub struct Request { | ||||
|     method: Method, | ||||
|     url: Url, | ||||
|     headers: HeaderMap, | ||||
|     body: Option<Body>, | ||||
| } | ||||
|  | ||||
| /// A builder to construct the properties of a `Request`. | ||||
| pub struct RequestBuilder { | ||||
|     client: Client, | ||||
|     request: crate::Result<Request>, | ||||
| } | ||||
|  | ||||
| impl Request { | ||||
|     pub(super) fn new(method: Method, url: Url) -> Self { | ||||
|         Request { | ||||
|             method, | ||||
|             url, | ||||
|             headers: HeaderMap::new(), | ||||
|             body: None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Get the method. | ||||
|     #[inline] | ||||
|     pub fn method(&self) -> &Method { | ||||
|         &self.method | ||||
|     } | ||||
|  | ||||
|     /// Get a mutable reference to the method. | ||||
|     #[inline] | ||||
|     pub fn method_mut(&mut self) -> &mut Method { | ||||
|         &mut self.method | ||||
|     } | ||||
|  | ||||
|     /// Get the url. | ||||
|     #[inline] | ||||
|     pub fn url(&self) -> &Url { | ||||
|         &self.url | ||||
|     } | ||||
|  | ||||
|     /// Get a mutable reference to the url. | ||||
|     #[inline] | ||||
|     pub fn url_mut(&mut self) -> &mut Url { | ||||
|         &mut self.url | ||||
|     } | ||||
|  | ||||
|     /// Get the headers. | ||||
|     #[inline] | ||||
|     pub fn headers(&self) -> &HeaderMap { | ||||
|         &self.headers | ||||
|     } | ||||
|  | ||||
|     /// Get a mutable reference to the headers. | ||||
|     #[inline] | ||||
|     pub fn headers_mut(&mut self) -> &mut HeaderMap { | ||||
|         &mut self.headers | ||||
|     } | ||||
|  | ||||
|     /// Get the body. | ||||
|     #[inline] | ||||
|     pub fn body(&self) -> Option<&Body> { | ||||
|         self.body.as_ref() | ||||
|     } | ||||
|  | ||||
|     /// Get a mutable reference to the body. | ||||
|     #[inline] | ||||
|     pub fn body_mut(&mut self) -> &mut Option<Body> { | ||||
|         &mut self.body | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl RequestBuilder { | ||||
|     pub(super) fn new(client: Client, request: crate::Result<Request>) -> 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 { | ||||
|             req.body = Some(body.into()); | ||||
|         } | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     /// Constructs the Request and sends it to the target URL, returning a | ||||
|     /// future Response. | ||||
|     /// | ||||
|     /// # Errors | ||||
|     /// | ||||
|     /// This method fails if there was an error while sending request. | ||||
|     /// | ||||
|     /// # Example | ||||
|     /// | ||||
|     /// ```no_run | ||||
|     /// # use reqwest::Error; | ||||
|     /// # | ||||
|     /// # async fn run() -> Result<(), Error> { | ||||
|     /// let response = reqwest::Client::new() | ||||
|     ///     .get("https://hyper.rs") | ||||
|     ///     .send() | ||||
|     ///     .await?; | ||||
|     /// # Ok(()) | ||||
|     /// # } | ||||
|     /// ``` | ||||
|     pub async fn send(self) -> crate::Result<Response> { | ||||
|         let req = self.request?; | ||||
|         self.client.execute_request(req).await | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Debug for Request { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         fmt_request_fields(&mut f.debug_struct("Request"), self).finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Debug for RequestBuilder { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         let mut builder = f.debug_struct("RequestBuilder"); | ||||
|         match self.request { | ||||
|             Ok(ref req) => fmt_request_fields(&mut builder, req).finish(), | ||||
|             Err(ref err) => builder.field("error", err).finish(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn fmt_request_fields<'a, 'b>( | ||||
|     f: &'a mut fmt::DebugStruct<'a, 'b>, | ||||
|     req: &Request, | ||||
| ) -> &'a mut fmt::DebugStruct<'a, 'b> { | ||||
|     f.field("method", &req.method) | ||||
|         .field("url", &req.url) | ||||
|         .field("headers", &req.headers) | ||||
| } | ||||
							
								
								
									
										73
									
								
								src/wasm/response.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/wasm/response.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| use std::fmt; | ||||
|  | ||||
| use http::{HeaderMap, StatusCode}; | ||||
|  | ||||
| /// A Response to a submitted `Request`. | ||||
| pub struct Response { | ||||
|     http: http::Response<web_sys::Response>, | ||||
| } | ||||
|  | ||||
| impl Response { | ||||
|     pub(super) fn new( | ||||
|         res: http::Response<web_sys::Response>, | ||||
|         //url: Url, | ||||
|     ) -> Response { | ||||
|         Response { | ||||
|             http: res, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Get the `StatusCode` of this `Response`. | ||||
|     #[inline] | ||||
|     pub fn status(&self) -> StatusCode { | ||||
|         self.http.status() | ||||
|     } | ||||
|  | ||||
|     /// Get the `Headers` of this `Response`. | ||||
|     #[inline] | ||||
|     pub fn headers(&self) -> &HeaderMap { | ||||
|         self.http.headers() | ||||
|     } | ||||
|  | ||||
|     /// Get a mutable reference to the `Headers` of this `Response`. | ||||
|     #[inline] | ||||
|     pub fn headers_mut(&mut self) -> &mut HeaderMap { | ||||
|         self.http.headers_mut() | ||||
|     } | ||||
|  | ||||
|     /* It might not be possible to detect this in JS? | ||||
|     /// Get the HTTP `Version` of this `Response`. | ||||
|     #[inline] | ||||
|     pub fn version(&self) -> Version { | ||||
|         self.http.version() | ||||
|     } | ||||
|     */ | ||||
|  | ||||
|     // pub async fn json() | ||||
|  | ||||
|  | ||||
|     /// Get the response text. | ||||
|     pub async fn text(self) -> crate::Result<String> { | ||||
|         let p = self.http.body().text() | ||||
|             .map_err(crate::error::wasm) | ||||
|             .map_err(crate::error::decode)?; | ||||
|         let js_val = super::promise::<wasm_bindgen::JsValue>(p) | ||||
|             .await | ||||
|             .map_err(crate::error::decode)?; | ||||
|         if let Some(s) = js_val.as_string() { | ||||
|             Ok(s) | ||||
|         } else { | ||||
|             Err(crate::error::decode("response.text isn't string")) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Debug for Response { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.debug_struct("Response") | ||||
|             //.field("url", self.url()) | ||||
|             .field("status", &self.status()) | ||||
|             .field("headers", self.headers()) | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user