diff --git a/src/async_impl/client.rs b/src/async_impl/client.rs
index 6bd44ef..ecb540b 100644
--- a/src/async_impl/client.rs
+++ b/src/async_impl/client.rs
@@ -772,7 +772,7 @@ impl Client {
}
pub(super) fn execute_request(&self, req: Request) -> Pending {
- let (method, url, mut headers, body) = req.pieces();
+ let (method, url, mut headers, body, timeout) = req.pieces();
// insert default headers in the request headers
// without overwriting already appended headers.
@@ -816,15 +816,15 @@ impl Client {
.body(body.into_stream())
.expect("valid request parts");
+ let timeout = timeout
+ .or(self.inner.request_timeout)
+ .map(|dur| tokio::time::delay_for(dur));
+
+
*req.headers_mut() = headers.clone();
let in_flight = self.inner.hyper.request(req);
- let timeout = self
- .inner
- .request_timeout
- .map(|dur| tokio::time::delay_for(dur));
-
Pending {
inner: PendingInner::Request(PendingRequest {
method,
diff --git a/src/async_impl/request.rs b/src/async_impl/request.rs
index 43f5a44..47364f7 100644
--- a/src/async_impl/request.rs
+++ b/src/async_impl/request.rs
@@ -2,6 +2,7 @@ use std::convert::TryFrom;
use std::fmt;
use std::future::Future;
use std::io::Write;
+use std::time::Duration;
use base64;
use base64::write::EncoderWriter as Base64Encoder;
@@ -23,6 +24,7 @@ pub struct Request {
url: Url,
headers: HeaderMap,
body: Option
,
+ timeout: Option,
}
/// A builder to construct the properties of a `Request`.
@@ -40,6 +42,7 @@ impl Request {
url,
headers: HeaderMap::new(),
body: None,
+ timeout: None
}
}
@@ -91,6 +94,18 @@ impl Request {
&mut self.body
}
+ /// Get the timeout.
+ #[inline]
+ pub fn timeout(&self) -> Option<&Duration> {
+ self.timeout.as_ref()
+ }
+
+ /// Get a mutable reference to the timeout.
+ #[inline]
+ pub fn timeout_mut(&mut self) -> &mut Option {
+ &mut self.timeout
+ }
+
/// Attempt to clone the request.
///
/// `None` is returned if the request can not be cloned, i.e. if the body is a stream.
@@ -100,13 +115,14 @@ impl Request {
None => None,
};
let mut req = Request::new(self.method().clone(), self.url().clone());
+ *req.timeout_mut() = self.timeout().cloned();
*req.headers_mut() = self.headers().clone();
req.body = body;
Some(req)
}
- pub(super) fn pieces(self) -> (Method, Url, HeaderMap, Option) {
- (self.method, self.url, self.headers, self.body)
+ pub(super) fn pieces(self) -> (Method, Url, HeaderMap, Option, Option) {
+ (self.method, self.url, self.headers, self.body, self.timeout)
}
}
@@ -199,6 +215,18 @@ impl RequestBuilder {
self
}
+ /// Enables a request timeout.
+ ///
+ /// The timeout is applied from the when the request starts connecting
+ /// until the response body has finished. It affects only this request
+ /// and overrides the timeout configured using `ClientBuilder::timeout()`.
+ pub fn timeout(mut self, timeout: Duration) -> RequestBuilder {
+ if let Ok(ref mut req) = self.request {
+ *req.timeout_mut() = Some(timeout);
+ }
+ self
+ }
+
/// Sends a multipart/form-data body.
///
/// ```
diff --git a/tests/timeouts.rs b/tests/timeouts.rs
index 2a68d9b..10663d4 100644
--- a/tests/timeouts.rs
+++ b/tests/timeouts.rs
@@ -4,7 +4,7 @@ use support::*;
use std::time::Duration;
#[tokio::test]
-async fn request_timeout() {
+async fn client_timeout() {
let _ = env_logger::try_init();
let server = server::http(move |_req| {
@@ -30,6 +30,34 @@ async fn request_timeout() {
assert_eq!(err.url().map(|u| u.as_str()), Some(url.as_str()));
}
+#[tokio::test]
+async fn request_timeout() {
+ let _ = env_logger::try_init();
+
+ let server = server::http(move |_req| {
+ async {
+ // delay returning the response
+ tokio::time::delay_for(Duration::from_secs(2)).await;
+ http::Response::default()
+ }
+ });
+
+ let client = reqwest::Client::builder().build().unwrap();
+
+ let url = format!("http://{}/slow", server.addr());
+
+ let res = client
+ .get(&url)
+ .timeout(Duration::from_millis(500))
+ .send()
+ .await;
+
+ let err = res.unwrap_err();
+
+ assert!(err.is_timeout());
+ assert_eq!(err.url().map(|u| u.as_str()), Some(url.as_str()));
+}
+
#[tokio::test]
async fn response_timeout() {
let _ = env_logger::try_init();