Make the blocking API an optional feature (default off)
This commit is contained in:
12
Cargo.toml
12
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"
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
11
src/error.rs
11
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: Into<BoxError>>(e: E) -> Error {
|
||||
Error::new(Kind::Request, Some(e))
|
||||
}
|
||||
|
||||
pub(crate) fn response<E: Into<BoxError>>(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::<Error>);
|
||||
assert!(root.source().is_none());
|
||||
|
||||
let link = super::response(root);
|
||||
let link = super::body(root);
|
||||
assert!(link.source().is_some());
|
||||
assert_send::<Error>();
|
||||
assert_sync::<Error>();
|
||||
@@ -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...
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user