From 7e3c1bc461dd51a9b59ca6b06b82e1699cc1a1ce Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Tue, 17 Sep 2019 15:06:10 -0700 Subject: [PATCH] Make the blocking API an optional feature (default off) --- Cargo.toml | 12 ++++++++++ src/async_impl/decoder.rs | 2 +- src/async_impl/response.rs | 1 + src/blocking/mod.rs | 8 +++++-- src/blocking/response.rs | 6 ++--- src/error.rs | 11 +++------ src/lib.rs | 2 ++ tests/gzip.rs | 49 +++++++++++++++++++------------------- tests/multipart.rs | 10 ++++---- tests/redirect.rs | 1 + tests/timeouts.rs | 18 ++++++++------ 11 files changed, 71 insertions(+), 49 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 91466bd..d02f71f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,6 +85,8 @@ default-tls-vendored = ["default-tls", "native-tls/vendored"] rustls-tls = ["hyper-rustls", "tokio-rustls", "webpki-roots", "rustls", "tls"] +blocking = [] + cookies = ["cookie_crate", "cookie_store"] #trust-dns = ["trust-dns-resolver"] @@ -92,6 +94,16 @@ cookies = ["cookie_crate", "cookie_store"] [target.'cfg(windows)'.dependencies] winreg = "0.6" +[[example]] +name = "blocking" +path = "examples/blocking.rs" +required-features = ["blocking"] + +[[test]] +name = "blocking" +path = "tests/blocking.rs" +required-features = ["blocking"] + [[test]] name = "cookie" path = "tests/cookie.rs" diff --git a/src/async_impl/decoder.rs b/src/async_impl/decoder.rs index e28049f..b785b69 100644 --- a/src/async_impl/decoder.rs +++ b/src/async_impl/decoder.rs @@ -60,7 +60,7 @@ impl Decoder { /// An empty decoder. /// /// This decoder will produce a single 0 byte chunk. - #[inline] + #[cfg(feature = "blocking")] pub(crate) fn empty() -> Decoder { Decoder { inner: Inner::PlainText(Body::empty().into_stream()), diff --git a/src/async_impl/response.rs b/src/async_impl/response.rs index 34b494d..9b51f0c 100644 --- a/src/async_impl/response.rs +++ b/src/async_impl/response.rs @@ -346,6 +346,7 @@ impl Response { // on the `Response` itself. // // This method is just used by the blocking API. + #[cfg(feature = "blocking")] pub(crate) fn body_mut(&mut self) -> &mut Decoder { &mut self.body } diff --git a/src/blocking/mod.rs b/src/blocking/mod.rs index dab76f6..4948cfb 100644 --- a/src/blocking/mod.rs +++ b/src/blocking/mod.rs @@ -3,7 +3,11 @@ //! The blocking `Client` will block the current thread to execute, instead //! of returning futures that need to be executed on a runtime. //! -//! ## Making a GET request +//! # Optional +//! +//! This requires the optional `blocking` feature to be enabled. +//! +//! # Making a GET request //! //! For a single request, you can use the [`get`](get) shortcut method. //! @@ -28,7 +32,7 @@ //! [`Client`](Client) and reuse it, taking advantage of keep-alive connection //! pooling. //! -//! ## Making POST requests (or setting request bodies) +//! # Making POST requests (or setting request bodies) //! //! There are several ways you can set the body of a request. The basic one is //! by using the `body()` method of a [`RequestBuilder`](RequestBuilder). This lets you set the diff --git a/src/blocking/response.rs b/src/blocking/response.rs index d5f5a76..92b9e1b 100644 --- a/src/blocking/response.rs +++ b/src/blocking/response.rs @@ -290,7 +290,7 @@ impl Response { where W: io::Write, { - io::copy(self, w).map_err(crate::error::response) + io::copy(self, w).map_err(crate::error::decode_io) } /// Turn a response into an error if the server returned an error. @@ -365,8 +365,8 @@ impl Read for Response { let timeout = self.timeout; wait::timeout(self.body_mut().read(buf), timeout).map_err(|e| match e { - wait::Waited::TimedOut(e) => crate::error::response(e).into_io(), - wait::Waited::Executor(e) => crate::error::response(e).into_io(), + wait::Waited::TimedOut(e) => crate::error::decode(e).into_io(), + wait::Waited::Executor(e) => crate::error::decode(e).into_io(), wait::Waited::Inner(e) => e, }) } diff --git a/src/error.rs b/src/error.rs index 89342c6..09039d3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -138,7 +138,6 @@ impl fmt::Display for Error { match self.inner.kind { Kind::Builder => f.write_str("builder error")?, Kind::Request => f.write_str("error sending request")?, - Kind::Response => f.write_str("error reading response")?, Kind::Body => f.write_str("request or response body error")?, Kind::Decode => f.write_str("error decoding response body")?, Kind::Redirect => f.write_str("error following redirect")?, @@ -173,7 +172,6 @@ impl StdError for Error { pub(crate) enum Kind { Builder, Request, - Response, Redirect, Status(StatusCode), Body, @@ -198,10 +196,6 @@ pub(crate) fn request>(e: E) -> Error { Error::new(Kind::Request, Some(e)) } -pub(crate) fn response>(e: E) -> Error { - Error::new(Kind::Response, Some(e)) -} - pub(crate) fn loop_detected(url: Url) -> Error { Error::new(Kind::Redirect, Some("infinite redirect loop detected")).with_url(url) } @@ -220,6 +214,7 @@ pub(crate) fn url_bad_scheme(url: Url) -> Error { // io::Error helpers +#[cfg(feature = "blocking")] pub(crate) fn into_io(e: Error) -> io::Error { e.into_io() } @@ -271,7 +266,7 @@ mod tests { let root = Error::new(Kind::Request, None::); assert!(root.source().is_none()); - let link = super::response(root); + let link = super::body(root); assert!(link.source().is_some()); assert_send::(); assert_sync::(); @@ -287,7 +282,7 @@ mod tests { fn roundtrip_io_error() { let orig = super::request("orig"); // Convert reqwest::Error into an io::Error... - let io = super::into_io(orig); + let io = orig.into_io(); // Convert that io::Error back into a reqwest::Error... let err = super::decode_io(io); // It should have pulled out the original, not nested it... diff --git a/src/lib.rs b/src/lib.rs index 1bfa050..3127621 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -156,6 +156,7 @@ //! `native-tls` library to connect over HTTPS. //! - **default-tls-vendored**: Enables the `vendored` feature of `native-tls`. //! - **rustls-tls**: Provides TLS support via the `rustls` library. +//! - **blocking**: Provides the [blocking][] client API. //! - **cookies**: Provides cookie session support. //! //! @@ -205,6 +206,7 @@ pub use self::tls::{Certificate, Identity}; mod error; mod async_impl; +#[cfg(feature = "blocking")] pub mod blocking; mod connect; #[cfg(feature = "cookies")] diff --git a/tests/gzip.rs b/tests/gzip.rs index c1bf596..f251c04 100644 --- a/tests/gzip.rs +++ b/tests/gzip.rs @@ -1,11 +1,11 @@ #[macro_use] mod support; -use std::io::{Read, Write}; +use std::io::Write; use std::time::Duration; -#[test] -fn test_gzip_response() { +#[tokio::test] +async fn test_gzip_response() { let content: String = (0..50).into_iter().map(|i| format!("test {}", i)).collect(); let chunk_size = content.len() / 3; let mut encoder = libflate::gzip::Encoder::new(Vec::new()).unwrap(); @@ -41,16 +41,16 @@ fn test_gzip_response() { write_timeout: Duration::from_millis(10), response: response }; - let mut res = reqwest::blocking::get(&format!("http://{}/gzip", server.addr())).unwrap(); + let url = format!("http://{}/gzip", server.addr()); + let res = reqwest::get(&url).await.unwrap(); - let mut body = String::new(); - res.read_to_string(&mut body).unwrap(); + let body = res.text().await.unwrap(); assert_eq!(body, content); } -#[test] -fn test_gzip_empty_body() { +#[tokio::test] +async fn test_gzip_empty_body() { let server = server! { request: b"\ HEAD /gzip HTTP/1.1\r\n\ @@ -68,20 +68,20 @@ fn test_gzip_empty_body() { \r\n" }; - let client = reqwest::blocking::Client::new(); - let mut res = client + let client = reqwest::Client::new(); + let res = client .head(&format!("http://{}/gzip", server.addr())) .send() + .await .unwrap(); - let mut body = std::string::String::new(); - res.read_to_string(&mut body).unwrap(); + let body = res.text().await.unwrap(); assert_eq!(body, ""); } -#[test] -fn test_gzip_invalid_body() { +#[tokio::test] +async fn test_gzip_invalid_body() { let server = server! { request: b"\ GET /gzip HTTP/1.1\r\n\ @@ -99,17 +99,16 @@ fn test_gzip_invalid_body() { \r\n\ 0" }; - - let mut res = reqwest::blocking::get(&format!("http://{}/gzip", server.addr())).unwrap(); + let url = format!("http://{}/gzip", server.addr()); + let res = reqwest::get(&url).await.unwrap(); // this tests that the request.send() didn't error, but that the error // is in reading the body - let mut body = std::string::String::new(); - res.read_to_string(&mut body).unwrap_err(); + res.text().await.unwrap_err(); } -#[test] -fn test_accept_header_is_not_changed_if_set() { +#[tokio::test] +async fn test_accept_header_is_not_changed_if_set() { let server = server! { request: b"\ GET /accept HTTP/1.1\r\n\ @@ -126,7 +125,7 @@ fn test_accept_header_is_not_changed_if_set() { \r\n\ " }; - let client = reqwest::blocking::Client::new(); + let client = reqwest::Client::new(); let res = client .get(&format!("http://{}/accept", server.addr())) @@ -135,13 +134,14 @@ fn test_accept_header_is_not_changed_if_set() { reqwest::header::HeaderValue::from_static("application/json"), ) .send() + .await .unwrap(); assert_eq!(res.status(), reqwest::StatusCode::OK); } -#[test] -fn test_accept_encoding_header_is_not_changed_if_set() { +#[tokio::test] +async fn test_accept_encoding_header_is_not_changed_if_set() { let server = server! { request: b"\ GET /accept-encoding HTTP/1.1\r\n\ @@ -158,7 +158,7 @@ fn test_accept_encoding_header_is_not_changed_if_set() { \r\n\ " }; - let client = reqwest::blocking::Client::new(); + let client = reqwest::Client::new(); let res = client .get(&format!("http://{}/accept-encoding", server.addr())) @@ -167,6 +167,7 @@ fn test_accept_encoding_header_is_not_changed_if_set() { reqwest::header::HeaderValue::from_static("identity"), ) .send() + .await .unwrap(); assert_eq!(res.status(), reqwest::StatusCode::OK); diff --git a/tests/multipart.rs b/tests/multipart.rs index 631ad81..5735c72 100644 --- a/tests/multipart.rs +++ b/tests/multipart.rs @@ -1,11 +1,11 @@ #[macro_use] mod support; -#[test] -fn text_part() { +#[tokio::test] +async fn text_part() { let _ = env_logger::try_init(); - let form = reqwest::blocking::multipart::Form::new().text("foo", "bar"); + let form = reqwest::multipart::Form::new().text("foo", "bar"); let expected_body = format!( "\ @@ -39,16 +39,18 @@ fn text_part() { let url = format!("http://{}/multipart/1", server.addr()); - let res = reqwest::blocking::Client::new() + let res = reqwest::Client::new() .post(&url) .multipart(form) .send() + .await .unwrap(); assert_eq!(res.url().as_str(), &url); assert_eq!(res.status(), reqwest::StatusCode::OK); } +#[cfg(feature = "blocking")] #[test] fn file() { let _ = env_logger::try_init(); diff --git a/tests/redirect.rs b/tests/redirect.rs index 78a0ae4..b2ece7b 100644 --- a/tests/redirect.rs +++ b/tests/redirect.rs @@ -165,6 +165,7 @@ async fn test_redirect_307_and_308_tries_to_post_again() { } } +#[cfg(feature = "blocking")] #[test] fn test_redirect_307_does_not_try_if_reader_cannot_reset() { let client = reqwest::blocking::Client::new(); diff --git a/tests/timeouts.rs b/tests/timeouts.rs index 320796f..84bf3ed 100644 --- a/tests/timeouts.rs +++ b/tests/timeouts.rs @@ -5,6 +5,7 @@ use std::time::Duration; /// Tests that internal client future cancels when the oneshot channel /// is canceled. +#[cfg(feature = "blocking")] #[test] fn timeout_closes_connection() { let _ = env_logger::try_init(); @@ -42,6 +43,7 @@ fn timeout_closes_connection() { assert_eq!(err.url().map(|u| u.as_str()), Some(url.as_str())); } +#[cfg(feature = "blocking")] #[test] fn write_timeout_large_body() { let _ = env_logger::try_init(); @@ -88,8 +90,8 @@ fn write_timeout_large_body() { assert_eq!(err.url().map(|u| u.as_str()), Some(url.as_str())); } -#[test] -fn test_response_timeout() { +#[tokio::test] +async fn test_response_timeout() { let _ = env_logger::try_init(); let server = server! { request: b"\ @@ -108,20 +110,21 @@ fn test_response_timeout() { }; let url = format!("http://{}/response-timeout", server.addr()); - let err = reqwest::blocking::Client::builder() + let err = reqwest::Client::builder() .timeout(Duration::from_millis(500)) .build() .unwrap() .get(&url) .send() + .await .unwrap_err(); assert!(err.is_timeout()); assert_eq!(err.url().map(|u| u.as_str()), Some(url.as_str())); } -#[test] -fn test_read_timeout() { +#[tokio::test] +async fn test_read_timeout() { let _ = env_logger::try_init(); let server = server! { request: b"\ @@ -142,12 +145,13 @@ fn test_read_timeout() { }; let url = format!("http://{}/read-timeout", server.addr()); - let res = reqwest::blocking::Client::builder() + let res = reqwest::Client::builder() .timeout(Duration::from_millis(500)) .build() .unwrap() .get(&url) .send() + .await .unwrap(); assert_eq!(res.url().as_str(), &url); @@ -157,6 +161,6 @@ fn test_read_timeout() { &"5" ); - let err = res.text().unwrap_err(); + let err = res.text().await.unwrap_err(); assert!(err.is_timeout()); }