diff --git a/CHANGES.md b/CHANGES.md index ea9a06f3..16bba10f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,7 +10,8 @@ * Add `ResponseError` impl for `SendRequestError`. This improves ergonomics of http client. - + +* Allow connection timeout to be set ## 0.4.4 (2018-03-04) diff --git a/Cargo.toml b/Cargo.toml index c56589df..d78f0792 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,7 +82,7 @@ openssl = { version="0.10", optional = true } tokio-openssl = { version="0.2", optional = true } [dependencies.actix] -version = "^0.5.1" +git = "https://github.com/actix/actix.git" [dev-dependencies] env_logger = "0.5" diff --git a/src/client/connector.rs b/src/client/connector.rs index 4e8ac214..eb9dc3b0 100644 --- a/src/client/connector.rs +++ b/src/client/connector.rs @@ -1,5 +1,6 @@ use std::{io, time}; use std::net::Shutdown; +use std::time::Duration; use actix::{fut, Actor, ActorFuture, Context, Handler, Message, ActorResponse, Supervised}; @@ -25,12 +26,18 @@ use server::IoStream; #[derive(Debug)] /// `Connect` type represents message that can be send to `ClientConnector` /// with connection request. -pub struct Connect(pub Uri); +pub struct Connect { + pub uri: Uri, + pub connection_timeout: Duration +} impl Connect { /// Create `Connect` message for specified `Uri` pub fn new(uri: U) -> Result where Uri: HttpTryFrom { - Ok(Connect(Uri::try_from(uri).map_err(|e| e.into())?)) + Ok(Connect { + uri: Uri::try_from(uri).map_err(|e| e.into())?, + connection_timeout: Duration::from_secs(1) + }) } } @@ -159,7 +166,8 @@ impl Handler for ClientConnector { type Result = ActorResponse; fn handle(&mut self, msg: Connect, _: &mut Self::Context) -> Self::Result { - let uri = &msg.0; + let uri = &msg.uri; + let connection_timeout = msg.connection_timeout; // host name is required if uri.host().is_none() { @@ -185,7 +193,7 @@ impl Handler for ClientConnector { ActorResponse::async( Connector::from_registry() - .send(ResolveConnect::host_and_port(&host, port)) + .send(ResolveConnect::host_and_port(&host, port).timeout(connection_timeout)) .into_actor(self) .map_err(|_, _, _| ClientConnectorError::Disconnected) .and_then(move |res, _act, _| { diff --git a/src/client/pipeline.rs b/src/client/pipeline.rs index baa84da9..47e38bc8 100644 --- a/src/client/pipeline.rs +++ b/src/client/pipeline.rs @@ -86,7 +86,10 @@ impl Future for SendRequest { match state { State::New => - self.state = State::Connect(self.conn.send(Connect(self.req.uri().clone()))), + self.state = State::Connect(self.conn.send(Connect { + uri: self.req.uri().clone(), + connection_timeout: self.req.connection_timeout() + })), State::Connect(mut conn) => match conn.poll() { Ok(Async::NotReady) => { self.state = State::Connect(conn); diff --git a/src/client/request.rs b/src/client/request.rs index a1f61d8d..d7ab2d53 100644 --- a/src/client/request.rs +++ b/src/client/request.rs @@ -1,5 +1,6 @@ use std::{fmt, mem}; use std::io::Write; +use std::time::Duration; use actix::{Addr, Unsync}; use cookie::{Cookie, CookieJar}; @@ -28,6 +29,7 @@ pub struct ClientRequest { response_decompress: bool, buffer_capacity: Option<(usize, usize)>, conn: ConnectionType, + connection_timeout: Duration } @@ -52,6 +54,7 @@ impl Default for ClientRequest { response_decompress: true, buffer_capacity: None, conn: ConnectionType::Default, + connection_timeout: Duration::from_secs(1) } } } @@ -102,7 +105,7 @@ impl ClientRequest { request: Some(ClientRequest::default()), err: None, cookies: None, - default_headers: true, + default_headers: true } } @@ -112,6 +115,11 @@ impl ClientRequest { &self.uri } + #[inline] + pub fn connection_timeout(&self) -> Duration { + self.connection_timeout + } + /// Set client request uri #[inline] pub fn set_uri(&mut self, uri: Uri) { @@ -236,7 +244,7 @@ pub struct ClientRequestBuilder { request: Option, err: Option, cookies: Option, - default_headers: bool, + default_headers: bool } impl ClientRequestBuilder { @@ -398,6 +406,15 @@ impl ClientRequestBuilder { self } + /// Set connection timeout + #[inline] + pub fn connection_timeout(&mut self, connection_timeout: Duration) -> &mut Self { + if let Some(ref mut request) = self.request { + request.connection_timeout = connection_timeout; + } + self + } + /// Set request's content type #[inline] pub fn content_type(&mut self, value: V) -> &mut Self @@ -599,7 +616,7 @@ impl ClientRequestBuilder { request: self.request.take(), err: self.err.take(), cookies: self.cookies.take(), - default_headers: self.default_headers, + default_headers: self.default_headers } } }