Add overall timeout for requests. (#67)
This deprecates timeout_read() and timeout_write() in favor of timeout(). The new timeout method on Request takes a Duration instead of a number of milliseconds, and is measured against overall request time, not per-read time. Once a request is started, the timeout is turned into a deadline specific to that call. The deadline is used in conjunction with the new DeadlineStream class, which sets a timeout on each read according to the remaining time for the request. Once the request is done, the DeadlineStream is unwrapped via .into::<Stream>() to become an undecorated Stream again for return to the pool. Timeouts on the stream are unset at this point. Still to be done: Add a setting on Agent for default timeout. Change header-writing code to apply overall deadline rather than per-write timeout. Fixes #28.
This commit is contained in:
committed by
GitHub
parent
d6b712f56f
commit
57be414d97
16
src/unit.rs
16
src/unit.rs
@@ -1,5 +1,6 @@
|
||||
use std::io::{Result as IoResult, Write};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time;
|
||||
|
||||
use qstring::QString;
|
||||
use url::Url;
|
||||
@@ -38,6 +39,7 @@ pub(crate) struct Unit {
|
||||
pub timeout_connect: u64,
|
||||
pub timeout_read: u64,
|
||||
pub timeout_write: u64,
|
||||
pub deadline: Option<time::Instant>,
|
||||
pub method: String,
|
||||
pub proxy: Option<Proxy>,
|
||||
#[cfg(feature = "tls")]
|
||||
@@ -89,6 +91,14 @@ impl Unit {
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let deadline = match req.timeout {
|
||||
None => None,
|
||||
Some(timeout) => {
|
||||
let now = time::Instant::now();
|
||||
Some(now.checked_add(timeout).unwrap())
|
||||
}
|
||||
};
|
||||
|
||||
Unit {
|
||||
agent: Arc::clone(&req.agent),
|
||||
url: url.clone(),
|
||||
@@ -98,6 +108,7 @@ impl Unit {
|
||||
timeout_connect: req.timeout_connect,
|
||||
timeout_read: req.timeout_read,
|
||||
timeout_write: req.timeout_write,
|
||||
deadline,
|
||||
method: req.method.clone(),
|
||||
proxy: req.proxy.clone(),
|
||||
#[cfg(feature = "tls")]
|
||||
@@ -154,6 +165,7 @@ pub(crate) fn connect(
|
||||
let body_bytes_sent = body::send_body(body, unit.is_chunked, &mut stream)?;
|
||||
|
||||
// start reading the response to process cookies and redirects.
|
||||
let mut stream = stream::DeadlineStream::new(stream, unit.deadline);
|
||||
let mut resp = Response::from_read(&mut stream);
|
||||
|
||||
if let Some(err) = resp.synthetic_error() {
|
||||
@@ -208,8 +220,8 @@ pub(crate) fn connect(
|
||||
}
|
||||
|
||||
// since it is not a redirect, or we're not following redirects,
|
||||
// give away the incoming stream to the response object
|
||||
crate::response::set_stream(&mut resp, unit.url.to_string(), Some(unit), stream);
|
||||
// give away the incoming stream to the response object.
|
||||
crate::response::set_stream(&mut resp, unit.url.to_string(), Some(unit), stream.into());
|
||||
|
||||
// release the response
|
||||
Ok(resp)
|
||||
|
||||
Reference in New Issue
Block a user