diff --git a/src/request.rs b/src/request.rs index 32f38cf..182d4b6 100644 --- a/src/request.rs +++ b/src/request.rs @@ -40,6 +40,7 @@ pub struct Request { error_on_non_2xx: bool, headers: Vec
, query_params: Vec<(String, String)>, + timeout: Option, } impl fmt::Display for Urlish { @@ -70,6 +71,7 @@ impl Request { headers: vec![], error_on_non_2xx: true, query_params: vec![], + timeout: None, } } @@ -81,9 +83,17 @@ impl Request { headers: vec![], error_on_non_2xx: true, query_params: vec![], + timeout: None, } } + #[inline(always)] + /// Sets overall timeout for the request, overriding agent's configuration if any. + pub fn timeout(mut self, timeout: time::Duration) -> Self { + self.timeout = Some(timeout); + self + } + /// Sends the request with no body and blocks the caller until done. /// /// Use this with GET, HEAD, OPTIONS or TRACE. It sends neither @@ -116,7 +126,7 @@ impl Request { for (name, value) in self.query_params.clone() { url.query_pairs_mut().append_pair(&name, &value); } - let deadline = match self.agent.config.timeout { + let deadline = match self.timeout.or(self.agent.config.timeout) { None => None, Some(timeout) => { let now = time::Instant::now(); diff --git a/src/test/timeout.rs b/src/test/timeout.rs index c6c1b6e..c46354b 100644 --- a/src/test/timeout.rs +++ b/src/test/timeout.rs @@ -124,6 +124,27 @@ fn overall_timeout_during_headers() { .expect("expected timeout but got something else"); } +#[test] +fn overall_timeout_override_during_headers() { + // Start a test server on an available port, that dribbles out a response at 1 write per 10ms. + let server = TestServer::new(dribble_headers_respond); + let url = format!("http://localhost:{}/", server.port); + let agent = builder().timeout(Duration::from_secs(90000)).build(); + let result = agent.get(&url).timeout(Duration::from_millis(500)).call(); + match result { + Ok(_) => Err("successful response".to_string()), + Err(e) if e.kind() == ErrorKind::Io => { + let ioe: Option<&io::Error> = e.source().and_then(|s| s.downcast_ref()); + match ioe { + Some(e) if e.kind() == io::ErrorKind::TimedOut => Ok(()), + _ => Err(format!("wrong error type {:?}", e)), + } + } + Err(e) => Err(format!("Unexpected error type: {:?}", e)), + } + .expect("expected timeout but got something else"); +} + #[test] #[cfg(feature = "json")] fn overall_timeout_reading_json() {