Skip to content

Commit

Permalink
feat(client): update construction of Clients
Browse files Browse the repository at this point in the history
- `Client::new()` no longer needs a `Handle`, and instead makes use of
  tokio's implicit default.
- Changed `Client::configure()` to `Client::builder()`.
- `Builder` is a by-ref builder, since all configuration is now
  cloneable pieces.

BREAKING CHANGE: `Client:new(&handle)` and `Client::configure()` are now
  `Client::new()` and `Client::builder()`.
  • Loading branch information
seanmonstar committed Apr 11, 2018
1 parent dfdca25 commit fe1578a
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 266 deletions.
2 changes: 1 addition & 1 deletion examples/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn main() {
}

tokio::run(lazy(move || {
let client = Client::default();
let client = Client::new();

let mut req = Request::new(Body::empty());
*req.uri_mut() = url;
Expand Down
11 changes: 5 additions & 6 deletions examples/web_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ extern crate tokio;

use futures::{Future, Stream};
use futures::future::lazy;
use tokio::reactor::Handle;

use hyper::{Body, Chunk, Client, Method, Request, Response, StatusCode};
use hyper::client::HttpConnector;
use hyper::server::{Http, Service};

#[allow(unused, deprecated)]
Expand All @@ -19,7 +19,7 @@ static URL: &str = "http://127.0.0.1:1337/web_api";
static INDEX: &[u8] = b"<a href=\"test.html\">test.html</a>";
static LOWERCASE: &[u8] = b"i am a lower case string";

struct ResponseExamples(Handle);
struct ResponseExamples(Client<HttpConnector>);

impl Service for ResponseExamples {
type Request = Request<Body>;
Expand All @@ -35,13 +35,12 @@ impl Service for ResponseExamples {
},
(&Method::GET, "/test.html") => {
// Run a web query against the web api below
let client = Client::configure().build(&self.0);
let req = Request::builder()
.method(Method::POST)
.uri(URL)
.body(LOWERCASE.into())
.unwrap();
let web_res_future = client.request(req);
let web_res_future = self.0.request(req);

Box::new(web_res_future.map(|web_res| {
let body = Body::wrap_stream(web_res.into_body().map(|b| {
Expand Down Expand Up @@ -79,8 +78,8 @@ fn main() {
let addr = "127.0.0.1:1337".parse().unwrap();

tokio::run(lazy(move || {
let handle = Handle::current();
let serve = Http::new().serve_addr(&addr, move || Ok(ResponseExamples(handle.clone()))).unwrap();
let client = Client::new();
let serve = Http::new().serve_addr(&addr, move || Ok(ResponseExamples(client.clone()))).unwrap();
println!("Listening on http://{} with 1 thread.", serve.incoming_ref().local_addr());

serve.map_err(|_| ()).for_each(move |conn| {
Expand Down
74 changes: 41 additions & 33 deletions src/client/connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,26 +135,30 @@ impl Connected {
*/
}

fn connect(addr: &SocketAddr, handle: &Handle) -> io::Result<ConnectFuture> {
let builder = match addr {
&SocketAddr::V4(_) => TcpBuilder::new_v4()?,
&SocketAddr::V6(_) => TcpBuilder::new_v6()?,
};

if cfg!(windows) {
// Windows requires a socket be bound before calling connect
let any: SocketAddr = match addr {
&SocketAddr::V4(_) => {
([0, 0, 0, 0], 0).into()
},
&SocketAddr::V6(_) => {
([0, 0, 0, 0, 0, 0, 0, 0], 0).into()
}
fn connect(addr: &SocketAddr, handle: &Option<Handle>) -> io::Result<ConnectFuture> {
if let Some(ref handle) = *handle {
let builder = match addr {
&SocketAddr::V4(_) => TcpBuilder::new_v4()?,
&SocketAddr::V6(_) => TcpBuilder::new_v6()?,
};
builder.bind(any)?;
}

Ok(TcpStream::connect_std(builder.to_tcp_stream()?, addr, handle))
if cfg!(windows) {
// Windows requires a socket be bound before calling connect
let any: SocketAddr = match addr {
&SocketAddr::V4(_) => {
([0, 0, 0, 0], 0).into()
},
&SocketAddr::V6(_) => {
([0, 0, 0, 0, 0, 0, 0, 0], 0).into()
}
};
builder.bind(any)?;
}

Ok(TcpStream::connect_std(builder.to_tcp_stream()?, addr, handle))
} else {
Ok(TcpStream::connect(addr))
}
}

/// A connector for the `http` scheme.
Expand All @@ -164,7 +168,7 @@ fn connect(addr: &SocketAddr, handle: &Handle) -> io::Result<ConnectFuture> {
pub struct HttpConnector {
executor: HttpConnectExecutor,
enforce_http: bool,
handle: Handle,
handle: Option<Handle>,
keep_alive_timeout: Option<Duration>,
}

Expand All @@ -173,7 +177,16 @@ impl HttpConnector {
///
/// Takes number of DNS worker threads.
#[inline]
pub fn new(threads: usize, handle: &Handle) -> HttpConnector {
pub fn new(threads: usize) -> HttpConnector {
HttpConnector::new_with_handle_opt(threads, None)
}

/// Construct a new HttpConnector with a specific Tokio handle.
pub fn new_with_handle(threads: usize, handle: Handle) -> HttpConnector {
HttpConnector::new_with_handle_opt(threads, Some(handle))
}

fn new_with_handle_opt(threads: usize, handle: Option<Handle>) -> HttpConnector {
let pool = CpuPoolBuilder::new()
.name_prefix("hyper-dns")
.pool_size(threads)
Expand All @@ -184,14 +197,13 @@ impl HttpConnector {
/// Construct a new HttpConnector.
///
/// Takes an executor to run blocking tasks on.
#[inline]
pub fn new_with_executor<E: 'static>(executor: E, handle: &Handle) -> HttpConnector
pub fn new_with_executor<E: 'static>(executor: E, handle: Option<Handle>) -> HttpConnector
where E: Executor<HttpConnectorBlockingTask> + Send + Sync
{
HttpConnector {
executor: HttpConnectExecutor(Arc::new(executor)),
enforce_http: true,
handle: handle.clone(),
handle,
keep_alive_timeout: None,
}
}
Expand Down Expand Up @@ -257,7 +269,7 @@ impl Connect for HttpConnector {
}

#[inline]
fn invalid_url(err: InvalidUrl, handle: &Handle) -> HttpConnecting {
fn invalid_url(err: InvalidUrl, handle: &Option<Handle>) -> HttpConnecting {
HttpConnecting {
state: State::Error(Some(io::Error::new(io::ErrorKind::InvalidInput, err))),
handle: handle.clone(),
Expand Down Expand Up @@ -292,7 +304,7 @@ impl StdError for InvalidUrl {
#[must_use = "futures do nothing unless polled"]
pub struct HttpConnecting {
state: State,
handle: Handle,
handle: Option<Handle>,
keep_alive_timeout: Option<Duration>,
}

Expand Down Expand Up @@ -365,7 +377,7 @@ struct ConnectingTcp {

impl ConnectingTcp {
// not a Future, since passing a &Handle to poll
fn poll(&mut self, handle: &Handle) -> Poll<TcpStream, io::Error> {
fn poll(&mut self, handle: &Option<Handle>) -> Poll<TcpStream, io::Error> {
let mut err = None;
loop {
if let Some(ref mut current) = self.current {
Expand Down Expand Up @@ -431,42 +443,38 @@ mod tests {
#![allow(deprecated)]
use std::io;
use futures::Future;
use tokio::runtime::Runtime;
use super::{Connect, Destination, HttpConnector};

#[test]
fn test_errors_missing_authority() {
let runtime = Runtime::new().unwrap();
let uri = "/foo/bar?baz".parse().unwrap();
let dst = Destination {
uri,
};
let connector = HttpConnector::new(1, runtime.handle());
let connector = HttpConnector::new(1);

assert_eq!(connector.connect(dst).wait().unwrap_err().kind(), io::ErrorKind::InvalidInput);
}

#[test]
fn test_errors_enforce_http() {
let runtime = Runtime::new().unwrap();
let uri = "https://example.domain/foo/bar?baz".parse().unwrap();
let dst = Destination {
uri,
};
let connector = HttpConnector::new(1, runtime.handle());
let connector = HttpConnector::new(1);

assert_eq!(connector.connect(dst).wait().unwrap_err().kind(), io::ErrorKind::InvalidInput);
}


#[test]
fn test_errors_missing_scheme() {
let runtime = Runtime::new().unwrap();
let uri = "example.domain".parse().unwrap();
let dst = Destination {
uri,
};
let connector = HttpConnector::new(1, runtime.handle());
let connector = HttpConnector::new(1);

assert_eq!(connector.connect(dst).wait().unwrap_err().kind(), io::ErrorKind::InvalidInput);
}
Expand Down
Loading

0 comments on commit fe1578a

Please sign in to comment.