From 00e53514ebab0c778570537e0336ee35143d7ce6 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Wed, 7 Aug 2019 13:53:47 +0200 Subject: [PATCH] WASM backend (#25) * init wasm client Signed-off-by: Yoshua Wuyts * wasm32 cfg flags Signed-off-by: Yoshua Wuyts * sort deps alphabetically Signed-off-by: Yoshua Wuyts * init cross platform by default Signed-off-by: Yoshua Wuyts * finish compile Signed-off-by: Yoshua Wuyts * wasm ci Signed-off-by: Yoshua Wuyts * move over cfg statements Signed-off-by: Yoshua Wuyts * make fetch Signed-off-by: Yoshua Wuyts * wasmify logging middleware Signed-off-by: Yoshua Wuyts * wip Signed-off-by: Yoshua Wuyts * add wasm kv logging Signed-off-by: Yoshua Wuyts * wasm compiles Signed-off-by: Yoshua Wuyts * update safety notice Signed-off-by: Yoshua Wuyts * requests work! Signed-off-by: Yoshua Wuyts * wasm req method Signed-off-by: Yoshua Wuyts * split out fetch code to separate block Signed-off-by: Yoshua Wuyts * fix all warnings Signed-off-by: Yoshua Wuyts * finalize header extraction Signed-off-by: Yoshua Wuyts --- .gitignore | 1 + .travis.yml | 4 +- Cargo.toml | 49 ++++- README.md | 7 +- examples/browser.rs | 7 + src/client.rs | 10 +- src/http_client/chttp.rs | 5 +- src/http_client/mod.rs | 10 +- src/http_client/native.rs | 8 + src/http_client/wasm.rs | 201 ++++++++++++++++++ src/lib.rs | 6 +- src/middleware/logger/mod.rs | 44 ++++ .../{logger.rs => logger/native.rs} | 40 +--- src/middleware/logger/wasm.rs | 108 ++++++++++ src/one_off.rs | 22 +- src/request.rs | 16 +- 16 files changed, 459 insertions(+), 79 deletions(-) create mode 100644 examples/browser.rs create mode 100644 src/http_client/native.rs create mode 100644 src/http_client/wasm.rs create mode 100644 src/middleware/logger/mod.rs rename src/middleware/{logger.rs => logger/native.rs} (80%) create mode 100644 src/middleware/logger/wasm.rs diff --git a/.gitignore b/.gitignore index ac0d3c7..97c1ae7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ dist/ npm-debug.log* Cargo.lock .DS_Store +wasm-pack.log diff --git a/.travis.yml b/.travis.yml index c70fb67..57e5aec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,12 @@ rust: before_script: | rustup component add rustfmt-preview && - rustup component add clippy-preview + rustup component add clippy-preview && + rustup target add wasm32-unknown-unknown script: | cargo fmt -- --check && cargo clippy -- -D clippy && cargo build --verbose && + cargo check --target wasm32-unknown-unknown && cargo test --verbose cache: cargo diff --git a/Cargo.toml b/Cargo.toml index 7bda17f..a544306 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,34 +12,61 @@ readme = "README.md" edition = "2018" [features] -default = ["chttp-client", "middleware-logger"] +default = ["native-client", "middleware-logger"] +native-client = ["chttp-client", "wasm-client"] hyper-client = ["hyper", "runtime", "runtime-raw", "runtime-tokio" ] chttp-client = ["chttp"] +wasm-client = ["js-sys", "web-sys", "wasm-bindgen", "wasm-bindgen-futures"] middleware-logger = [] [dependencies] -http = "0.1.17" futures-preview = { version = "0.3.0-alpha.17", features = ["compat", "io-compat"] } +http = "0.1.17" +log = { version = "0.4.7", features = ["kv_unstable"] } +mime = "0.3.13" +mime_guess = "2.0.0-alpha.6" serde = "1.0.97" serde_json = "1.0.40" -log = { version = "0.4.7", features = ["kv_unstable"] } +serde_urlencoded = "0.6.1" url = "2.0.0" -mime_guess = "2.0.0-alpha.6" -mime = "0.3.13" -# Chttp +# chttp-client +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] chttp = { version = "0.5.3", optional = true } -# Hyper deps +# hyper-client hyper = { version = "0.12.32", optional = true, default-features = false } hyper-tls = { version = "0.3.2", optional = true } -runtime = { version = "0.3.0-alpha.6", optional = true } native-tls = { version = "0.2.2", optional = true } +runtime = { version = "0.3.0-alpha.6", optional = true } runtime-raw = { version = "0.3.0-alpha.4", optional = true } runtime-tokio = { version = "0.3.0-alpha.5", optional = true } -serde_urlencoded = "0.6.1" + +# wasm-client +[target.'cfg(target_arch = "wasm32")'.dependencies] +js-sys = { version = "0.3.25", optional = true } +wasm-bindgen = { version = "0.2.48", optional = true } +wasm-bindgen-futures = { version = "0.3.25", features = ["futures_0_3"], optional = true } + +[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys] +version = "0.3.25" +optional = true +features = [ + "AbortSignal", + "Headers", + "ObserverCallback", + "ReferrerPolicy", + "Request", + "RequestCache", + "RequestCredentials", + "RequestInit", + "RequestMode", + "RequestRedirect", + "Response", + "Window", +] [dev-dependencies] -serde = { version = "1.0.97", features = ["derive"] } -runtime = "0.3.0-alpha.6" femme = "1.1.0" +runtime = "0.3.0-alpha.6" +serde = { version = "1.0.97", features = ["derive"] } diff --git a/README.md b/README.md index 10b6af4..20b503d 100644 --- a/README.md +++ b/README.md @@ -124,8 +124,11 @@ $ cargo add surf ``` ## Safety -This crate uses ``#![deny(unsafe_code)]`` to ensure everything is implemented in -100% Safe Rust. +This crate makes use of a single instance of `unsafe` in order to make the WASM +backend work despite the `Send` bounds. This is safe because WASM targets +currently have no access to threads. Once they do we'll be able to drop this +implementation, and use a parked thread instead and move to full multi-threading +in the process too. ## Contributing Want to join us? Check out our ["Contributing" guide][contributing] and take a diff --git a/examples/browser.rs b/examples/browser.rs new file mode 100644 index 0000000..32a69ab --- /dev/null +++ b/examples/browser.rs @@ -0,0 +1,7 @@ +use surf; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen(start)] +pub fn main() { + println!("Hello wasm"); +} diff --git a/src/client.rs b/src/client.rs index 669ca11..8df0c11 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,8 +1,8 @@ use crate::http_client::HttpClient; use crate::Request; -#[cfg(feature = "chttp-client")] -use crate::http_client::chttp::ChttpClient; +#[cfg(feature = "native-client")] +use super::http_client::native::NativeClient; /// An HTTP client, capable of creating new `Request`s. /// @@ -23,8 +23,8 @@ pub struct Client { client: C, } -#[cfg(feature = "chttp-client")] -impl Client { +#[cfg(feature = "native-client")] +impl Client { /// Create a new instance. /// /// # Examples @@ -37,7 +37,7 @@ impl Client { /// # Ok(()) } /// ``` pub fn new() -> Self { - Self::with_client(ChttpClient::new()) + Self::with_client(NativeClient::new()) } } diff --git a/src/http_client/chttp.rs b/src/http_client/chttp.rs index 8fdfb21..8266600 100644 --- a/src/http_client/chttp.rs +++ b/src/http_client/chttp.rs @@ -4,10 +4,7 @@ use futures::future::BoxFuture; use std::sync::Arc; -/// Curl HTTP Client. -/// -/// ## Performance -/// Libcurl is not thread safe, which means unfortunatley we cannot reuse connections or multiplex. +/// Curl-based HTTP Client. #[derive(Debug)] pub struct ChttpClient { client: Arc, diff --git a/src/http_client/mod.rs b/src/http_client/mod.rs index 0bec478..57c0e1e 100644 --- a/src/http_client/mod.rs +++ b/src/http_client/mod.rs @@ -8,12 +8,18 @@ use std::io; use std::pin::Pin; use std::task::{Context, Poll}; -#[cfg(feature = "hyper-client")] +#[cfg(all(feature = "hyper-client", not(target_arch = "wasm32")))] pub(crate) mod hyper; -#[cfg(feature = "chttp-client")] +#[cfg(all(feature = "chttp-client", not(target_arch = "wasm32")))] pub(crate) mod chttp; +#[cfg(all(feature = "wasm-client", target_arch = "wasm32"))] +pub(crate) mod wasm; + +#[cfg(feature = "native-client")] +pub(crate) mod native; + /// An HTTP Request type with a streaming body. pub type Request = http::Request; diff --git a/src/http_client/native.rs b/src/http_client/native.rs new file mode 100644 index 0000000..9fead48 --- /dev/null +++ b/src/http_client/native.rs @@ -0,0 +1,8 @@ +#[cfg(all(feature = "chttp-client", not(target_arch = "wasm32")))] +pub(crate) use super::chttp::ChttpClient as NativeClient; + +#[cfg(all( + feature = "wasm-client", + target_arch = "wasm32" +))] +pub(crate) use super::wasm::WasmClient as NativeClient; diff --git a/src/http_client/wasm.rs b/src/http_client/wasm.rs new file mode 100644 index 0000000..9ccfe93 --- /dev/null +++ b/src/http_client/wasm.rs @@ -0,0 +1,201 @@ +use super::{Body, HttpClient, Request, Response}; + +use futures::future::BoxFuture; +use futures::prelude::*; + +use std::pin::Pin; +use std::task::{Context, Poll}; +use std::io; + +/// WebAssembly HTTP Client. +#[derive(Debug)] +pub struct WasmClient { + _priv: (), +} + +impl WasmClient { + /// Create a new instance. + pub fn new() -> Self { + Self { _priv: () } + } +} + +impl Clone for WasmClient { + fn clone(&self) -> Self { + Self { _priv: () } + } +} + +impl HttpClient for WasmClient { + type Error = std::io::Error; + + fn send(&self, req: Request) -> BoxFuture<'static, Result> { + let fut = Box::pin(async move { + let url = format!("{}", req.uri()); + let req = fetch::new(req.method().as_str(), &url); + let mut res = req.send().await?; + + let body = res.body_bytes(); + let mut response = Response::new(Body::from(body)); + *response.status_mut() = http::StatusCode::from_u16(res.status()).unwrap(); + + for (name, value) in res.headers() { + let name: http::header::HeaderName = name.parse().unwrap(); + response.headers_mut().insert(name, value.parse().unwrap()); + } + + Ok(response) + }); + + Box::pin(InnerFuture { fut }) + } +} + +// This type e +struct InnerFuture { + fut: Pin> + 'static>>, +} + +// This is safe because WASM doesn't have threads yet. Once WASM supports threads we should use a +// thread to park the blocking implementation until it's been completed. +unsafe impl Send for InnerFuture {} + +impl Future for InnerFuture { + type Output = Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // This is safe because we're only using this future as a pass-through for the inner + // future, in order to implement `Send`. If it's safe to poll the inner future, it's safe + // to proxy it too. + unsafe { Pin::new_unchecked(&mut self.fut).poll(cx) } + } +} + +mod fetch { + use js_sys::{Array, ArrayBuffer, Uint8Array, Reflect}; + use wasm_bindgen::JsCast; + use wasm_bindgen_futures::futures_0_3::JsFuture; + use web_sys::window; + use web_sys::RequestInit; + + use std::iter::{Iterator, IntoIterator}; + use std::io; + + /// Create a new fetch request. + pub(crate) fn new(method: impl AsRef, url: impl AsRef) -> Request { + Request::new(method, url) + } + + /// An HTTP Fetch Request. + pub(crate) struct Request { + init: RequestInit, + url: String, + } + + impl Request { + /// Create a new instance. + pub(crate) fn new(method: impl AsRef, url: impl AsRef) -> Self { + let mut init = web_sys::RequestInit::new(); + init.method(method.as_ref()); + Self { + init, + url: url.as_ref().to_owned(), + } + } + + /// Submit a request + // TODO(yoshuawuyts): turn this into a `Future` impl on `Request` instead. + pub(crate) async fn send(self) -> Result { + // Send the request. + let window = window().expect("A global window object could not be found"); + let request = web_sys::Request::new_with_str_and_init(&self.url, &self.init).unwrap(); + let promise = window.fetch_with_request(&request); + let resp = JsFuture::from(promise).await.unwrap(); + debug_assert!(resp.is_instance_of::()); + let res: web_sys::Response = resp.dyn_into().unwrap(); + + // Get the request body. + let promise = res.array_buffer().unwrap(); + let resp = JsFuture::from(promise).await.unwrap(); + debug_assert!(resp.is_instance_of::()); + let buf: ArrayBuffer = resp.dyn_into().unwrap(); + let slice = Uint8Array::new(&buf); + let mut body: Vec = vec![0; slice.length() as usize]; + slice.copy_to(&mut body); + + Ok(Response::new(res, body)) + } + } + + /// An HTTP Fetch Response. + pub(crate) struct Response { + res: web_sys::Response, + body: Option>, + } + + impl Response { + fn new(res: web_sys::Response, body: Vec) -> Self { + Self { + res, + body: Some(body), + } + } + + /// Access the HTTP headers. + pub(crate) fn headers(&self) -> Headers { + Headers { + headers: self.res.headers() + } + } + + /// Get the request body as a byte vector. + /// + /// Returns an empty vector if the body has already been consumed. + pub(crate) fn body_bytes(&mut self) -> Vec { + self.body.take().unwrap_or_else(|| vec![]) + } + + /// Get the HTTP return status code. + pub(crate) fn status(&self) -> u16 { + self.res.status() + } + } + + /// HTTP Headers. + pub(crate) struct Headers { + headers: web_sys::Headers, + } + + impl IntoIterator for Headers { + type Item = (String, String); + type IntoIter = HeadersIter; + + fn into_iter(self) -> Self::IntoIter { + HeadersIter { + iter: js_sys::try_iter(&self.headers).unwrap().unwrap(), + } + } + } + + /// HTTP Headers Iterator. + pub(crate) struct HeadersIter { + iter: js_sys::IntoIter, + } + + impl Iterator for HeadersIter { + type Item = (String, String); + + fn next(&mut self) -> Option { + let pair = self.iter.next()?; + + let array: Array = pair.unwrap().into(); + let vals = array.values(); + + let prop = String::from("value").into(); + let key = Reflect::get(&vals.next().unwrap(), &prop).unwrap(); + let value = Reflect::get(&vals.next().unwrap(), &prop).unwrap(); + + Some((key.as_string().to_owned().unwrap(), value.as_string().to_owned().unwrap())) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index b417e58..5487984 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,7 +70,7 @@ //! - __`hyper-client`:__ use `hyper` as the HTTP backend. //! - __`middleware-logger` (default):__ enables logging requests and responses using a middleware. -#![forbid(unsafe_code, future_incompatible, rust_2018_idioms)] +#![forbid(future_incompatible, rust_2018_idioms)] #![deny(missing_debug_implementations, nonstandard_style)] #![warn(missing_docs, missing_doc_code_examples, unreachable_pub)] #![cfg_attr(test, deny(warnings))] @@ -91,9 +91,9 @@ pub use client::Client; pub use request::Request; pub use response::Response; -#[cfg(feature = "chttp-client")] +#[cfg(feature = "native-client")] mod one_off; -#[cfg(feature = "chttp-client")] +#[cfg(feature = "native-client")] pub use one_off::{connect, delete, get, head, options, patch, post, put, trace}; /// A generic error type. diff --git a/src/middleware/logger/mod.rs b/src/middleware/logger/mod.rs new file mode 100644 index 0000000..475c9d2 --- /dev/null +++ b/src/middleware/logger/mod.rs @@ -0,0 +1,44 @@ +//! Logging middleware. +//! +//! # Examples +//! +//! ``` +//! # #![feature(async_await)] +//! # #[runtime::main] +//! # async fn main() -> Result<(), Box> { +//! let mut res = surf::get("https://google.com") +//! .middleware(surf::middleware::logger::new()) +//! .await?; +//! dbg!(res.body_string().await?); +//! # Ok(()) } +//! ``` + +#[cfg(target_arch = "wasm32")] +mod wasm; + +#[cfg(target_arch = "wasm32")] +use wasm::Logger; + +#[cfg(not(target_arch = "wasm32"))] +mod native; + +#[cfg(not(target_arch = "wasm32"))] +use native::Logger; + +/// Create a new instance. +/// +/// # Examples +/// +/// ``` +/// # #![feature(async_await)] +/// # #[runtime::main] +/// # async fn main() -> Result<(), Box> { +/// let mut res = surf::get("https://google.com") +/// .middleware(surf::middleware::logger::new()) +/// .await?; +/// dbg!(res.body_string().await?); +/// # Ok(()) } +/// ``` +pub fn new() -> Logger { + Logger::new() +} diff --git a/src/middleware/logger.rs b/src/middleware/logger/native.rs similarity index 80% rename from src/middleware/logger.rs rename to src/middleware/logger/native.rs index f98dac6..9f1ee43 100644 --- a/src/middleware/logger.rs +++ b/src/middleware/logger/native.rs @@ -1,18 +1,3 @@ -//! Logging middleware. -//! -//! # Examples -//! -//! ``` -//! # #![feature(async_await)] -//! # #[runtime::main] -//! # async fn main() -> Result<(), Box> { -//! let mut res = surf::get("https://google.com") -//! .middleware(surf::middleware::logger::new()) -//! .await?; -//! dbg!(res.body_string().await?); -//! # Ok(()) } -//! ``` - use crate::http_client::HttpClient; use crate::middleware::{Middleware, Next, Request, Response}; @@ -29,6 +14,13 @@ pub struct Logger { _priv: (), } +impl Logger { + /// Create a new instance. + pub fn new() -> Self{ + Logger {_priv: ()} + } +} + impl Middleware for Logger { #[allow(missing_doc_code_examples)] fn handle<'a>( @@ -79,24 +71,6 @@ impl Middleware for Logger { } } -/// Create a new instance. -/// -/// # Examples -/// -/// ``` -/// # #![feature(async_await)] -/// # #[runtime::main] -/// # async fn main() -> Result<(), Box> { -/// let mut res = surf::get("https://google.com") -/// .middleware(surf::middleware::logger::new()) -/// .await?; -/// dbg!(res.body_string().await?); -/// # Ok(()) } -/// ``` -pub fn new() -> Logger { - Logger { _priv: () } -} - struct RequestPairs<'a> { id: usize, method: &'a str, diff --git a/src/middleware/logger/wasm.rs b/src/middleware/logger/wasm.rs new file mode 100644 index 0000000..5e453f9 --- /dev/null +++ b/src/middleware/logger/wasm.rs @@ -0,0 +1,108 @@ +use crate::http_client::HttpClient; +use crate::middleware::{Middleware, Next, Request, Response}; + +use futures::future::BoxFuture; + +use std::fmt::Arguments; + +/// Log each request's duration. +#[derive(Debug)] +pub struct Logger { + _priv: (), +} + +impl Logger { + /// Create a new instance. + pub fn new() -> Self{ + Logger {_priv: ()} + } +} + +impl Middleware for Logger { + #[allow(missing_doc_code_examples)] + fn handle<'a>( + &'a self, + req: Request, + client: C, + next: Next<'a, C>, + ) -> BoxFuture<'a, Result> { + Box::pin(async move { + let uri = format!("{}", req.uri()); + let method = format!("{}", req.method()); + print( + log::Level::Info, + format_args!("sending request"), + RequestPairs { + uri: &uri, + method: &method, + }, + ); + + let res = next.run(req, client).await?; + + let status = res.status(); + let level = if status.is_server_error() { + log::Level::Error + } else if status.is_client_error() { + log::Level::Warn + } else { + log::Level::Info + }; + + print( + level, + format_args!("request completed"), + ResponsePairs { + status: status.as_u16(), + }, + ); + Ok(res) + }) + } +} + +struct RequestPairs<'a> { + method: &'a str, + uri: &'a str, +} +impl<'a> log::kv::Source for RequestPairs<'a> { + fn visit<'kvs>( + &'kvs self, + visitor: &mut dyn log::kv::Visitor<'kvs>, + ) -> Result<(), log::kv::Error> { + visitor.visit_pair("req.method".into(), self.method.into())?; + visitor.visit_pair("req.uri".into(), self.uri.into())?; + Ok(()) + } +} + +struct ResponsePairs { + status: u16, +} + +impl log::kv::Source for ResponsePairs { + fn visit<'kvs>( + &'kvs self, + visitor: &mut dyn log::kv::Visitor<'kvs>, + ) -> Result<(), log::kv::Error> { + visitor.visit_pair("req.status".into(), self.status.into())?; + Ok(()) + } +} + + +fn print(level: log::Level, msg: Arguments<'_>, key_values: impl log::kv::Source) { + if level <= log::STATIC_MAX_LEVEL && level <= log::max_level() { + log::logger().log( + &log::Record::builder() + .args(msg) + .key_values(&key_values) + .level(level) + .target(module_path!()) + .module_path(Some(module_path!())) + .file(Some(file!())) + .line(Some(line!())) + .build(), + ); + } +} diff --git a/src/one_off.rs b/src/one_off.rs index 7a9f0b9..ddae62b 100644 --- a/src/one_off.rs +++ b/src/one_off.rs @@ -1,4 +1,6 @@ -use super::http_client::chttp::ChttpClient; +#[cfg(feature = "native-client")] +use super::http_client::native::NativeClient; + use super::Request; /// Perform a one-off `GET` request. @@ -29,7 +31,7 @@ use super::Request; /// let string = surf::get("https://httpbin.org/get").recv_string().await?; /// # Ok(()) } /// ``` -pub fn get(uri: impl AsRef) -> Request { +pub fn get(uri: impl AsRef) -> Request { let uri = uri.as_ref().to_owned().parse().unwrap(); Request::new(http::Method::GET, uri) } @@ -71,7 +73,7 @@ pub fn get(uri: impl AsRef) -> Request { /// let string = surf::head("https://httpbin.org/head").recv_string().await?; /// # Ok(()) } /// ``` -pub fn head(uri: impl AsRef) -> Request { +pub fn head(uri: impl AsRef) -> Request { let uri = uri.as_ref().to_owned().parse().unwrap(); Request::new(http::Method::HEAD, uri) } @@ -130,7 +132,7 @@ pub fn head(uri: impl AsRef) -> Request { /// let string = surf::post("https://httpbin.org/post").recv_string().await?; /// # Ok(()) } /// ``` -pub fn post(uri: impl AsRef) -> Request { +pub fn post(uri: impl AsRef) -> Request { let uri = uri.as_ref().to_owned().parse().unwrap(); Request::new(http::Method::POST, uri) } @@ -167,7 +169,7 @@ pub fn post(uri: impl AsRef) -> Request { /// let string = surf::put("https://httpbin.org/put").recv_string().await?; /// # Ok(()) } /// ``` -pub fn put(uri: impl AsRef) -> Request { +pub fn put(uri: impl AsRef) -> Request { let uri = uri.as_ref().to_owned().parse().unwrap(); Request::new(http::Method::PUT, uri) } @@ -199,7 +201,7 @@ pub fn put(uri: impl AsRef) -> Request { /// let string = surf::delete("https://httpbin.org/delete").recv_string().await?; /// # Ok(()) } /// ``` -pub fn delete(uri: impl AsRef) -> Request { +pub fn delete(uri: impl AsRef) -> Request { let uri = uri.as_ref().to_owned().parse().unwrap(); Request::new(http::Method::DELETE, uri) } @@ -240,7 +242,7 @@ pub fn delete(uri: impl AsRef) -> Request { /// let string = surf::connect("https://httpbin.org/connect").recv_string().await?; /// # Ok(()) } /// ``` -pub fn connect(uri: impl AsRef) -> Request { +pub fn connect(uri: impl AsRef) -> Request { let uri = uri.as_ref().to_owned().parse().unwrap(); Request::new(http::Method::CONNECT, uri) } @@ -274,7 +276,7 @@ pub fn connect(uri: impl AsRef) -> Request { /// let string = surf::options("https://httpbin.org/options").recv_string().await?; /// # Ok(()) } /// ``` -pub fn options(uri: impl AsRef) -> Request { +pub fn options(uri: impl AsRef) -> Request { let uri = uri.as_ref().to_owned().parse().unwrap(); Request::new(http::Method::OPTIONS, uri) } @@ -312,7 +314,7 @@ pub fn options(uri: impl AsRef) -> Request { /// let string = surf::trace("https://httpbin.org/trace").recv_string().await?; /// # Ok(()) } /// ``` -pub fn trace(uri: impl AsRef) -> Request { +pub fn trace(uri: impl AsRef) -> Request { let uri = uri.as_ref().to_owned().parse().unwrap(); Request::new(http::Method::TRACE, uri) } @@ -356,7 +358,7 @@ pub fn trace(uri: impl AsRef) -> Request { /// let string = surf::patch("https://httpbin.org/patch").recv_string().await?; /// # Ok(()) } /// ``` -pub fn patch(uri: impl AsRef) -> Request { +pub fn patch(uri: impl AsRef) -> Request { let uri = uri.as_ref().to_owned().parse().unwrap(); Request::new(http::Method::PATCH, uri) } diff --git a/src/request.rs b/src/request.rs index 8530967..370824d 100644 --- a/src/request.rs +++ b/src/request.rs @@ -20,9 +20,9 @@ use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll}; -#[cfg(feature = "chttp-client")] -use super::http_client::chttp::ChttpClient; -#[cfg(feature = "chttp-client")] +#[cfg(feature = "native-client")] +use super::http_client::native::NativeClient; +#[cfg(feature = "native-client")] use std::convert::TryFrom; /// An HTTP request, returns a `Response`. @@ -39,8 +39,8 @@ pub struct Request { url: Url, } -#[cfg(feature = "chttp-client")] -impl Request { +#[cfg(feature = "native-client")] +impl Request { /// Create a new instance. /// /// This method is particularly useful when input URLs might be passed by third parties, and @@ -61,7 +61,7 @@ impl Request { /// # Ok(()) } /// ``` pub fn new(method: http::Method, url: Url) -> Self { - Self::with_client(method, url, ChttpClient::new()) + Self::with_client(method, url, NativeClient::new()) } } @@ -563,9 +563,9 @@ impl Future for Request { } } -#[cfg(feature = "chttp-client")] +#[cfg(feature = "native-client")] impl TryFrom>> - for Request + for Request { type Error = io::Error;