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
@@ -1,12 +1,13 @@
|
||||
use std::io::{Cursor, Error as IoError, ErrorKind, Read, Result as IoResult};
|
||||
use std::str::FromStr;
|
||||
use std::time::Instant;
|
||||
|
||||
use chunked_transfer::Decoder as ChunkDecoder;
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::header::Header;
|
||||
use crate::pool::PoolReturnRead;
|
||||
use crate::stream::Stream;
|
||||
use crate::stream::{DeadlineStream, Stream};
|
||||
use crate::unit::Unit;
|
||||
|
||||
#[cfg(feature = "json")]
|
||||
@@ -46,6 +47,7 @@ pub struct Response {
|
||||
headers: Vec<Header>,
|
||||
unit: Option<Unit>,
|
||||
stream: Option<Stream>,
|
||||
deadline: Option<Instant>,
|
||||
}
|
||||
|
||||
/// index into status_line where we split: HTTP/1.1 200 OK
|
||||
@@ -273,7 +275,6 @@ impl Response {
|
||||
/// ```
|
||||
pub fn into_reader(self) -> impl Read {
|
||||
//
|
||||
|
||||
let is_http10 = self.http_version().eq_ignore_ascii_case("HTTP/1.0");
|
||||
let is_close = self
|
||||
.header("connection")
|
||||
@@ -306,6 +307,8 @@ impl Response {
|
||||
|
||||
let stream = self.stream.expect("No reader in response?!");
|
||||
let unit = self.unit;
|
||||
let deadline = unit.as_ref().and_then(|u| u.deadline);
|
||||
let stream = DeadlineStream::new(stream, deadline);
|
||||
|
||||
match (use_chunked, limit_bytes) {
|
||||
(true, _) => {
|
||||
@@ -472,6 +475,7 @@ impl Response {
|
||||
headers,
|
||||
unit: None,
|
||||
stream: None,
|
||||
deadline: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -551,6 +555,9 @@ impl Into<Response> for Error {
|
||||
/// *Internal API*
|
||||
pub(crate) fn set_stream(resp: &mut Response, url: String, unit: Option<Unit>, stream: Stream) {
|
||||
resp.url = Some(url);
|
||||
if let Some(unit) = &unit {
|
||||
resp.deadline = unit.deadline;
|
||||
}
|
||||
resp.unit = unit;
|
||||
resp.stream = Some(stream);
|
||||
}
|
||||
@@ -586,7 +593,7 @@ struct LimitedRead<R> {
|
||||
position: usize,
|
||||
}
|
||||
|
||||
impl<R> LimitedRead<R> {
|
||||
impl<R: Read> LimitedRead<R> {
|
||||
fn new(reader: R, limit: usize) -> Self {
|
||||
LimitedRead {
|
||||
reader,
|
||||
@@ -617,7 +624,7 @@ impl<R: Read> Read for LimitedRead<R> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<LimitedRead<R>> for Stream
|
||||
impl<R: Read> From<LimitedRead<R>> for Stream
|
||||
where
|
||||
Stream: From<R>,
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user