diff --git a/src/client/mod.rs b/src/client/mod.rs index 3d55d82f..eb03afc7 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1,4 +1,76 @@ //! HTTP Client +//! +//! There are two levels of APIs provided for construct HTTP clients: +//! +//! - The higher-level [`Client`](Client) type. +//! - The lower-level [conn](conn) module. +//! +//! # Client +//! +//! The [`Client`](Client) is the main way to send HTTP requests to a server. +//! The default `Client` provides these things on top of the lower-level API: +//! +//! - A default **connector**, able to resolve hostnames and connect to +//! destinations over plain-text TCP. +//! - A **pool** of existing connections, allowing better performance when +//! making multiple requests to the same hostname. +//! - Automatic setting of the `Host` header, based on the request `Uri`. +//! - Automatic request **retries** when a pooled connection is closed by the +//! server before any bytes have been written. +//! +//! Many of these features can configured, by making use of +//! [`Client::builder`](Client::builder). +//! +//! ## Example +//! +//! ```no_run +//! extern crate hyper; +//! +//! use hyper::Client; +//! # #[cfg(feature = "runtime")] +//! use hyper::rt::{self, lazy, Future, Stream}; +//! +//! # #[cfg(feature = "runtime")] +//! fn main() { +//! // A runtime is needed to execute our asynchronous code. +//! rt::run(lazy(|| { +//! let client = Client::new(); +//! +//! client +//! // Make a GET /ip to 'http://httpbin.org' +//! .get("http://httpbin.org/ip".parse().unwrap()) +//! +//! // And then, if the request gets a response... +//! .and_then(|res| { +//! println!("status: {}", res.status()); +//! +//! // Concatenate the body stream into a single buffer... +//! // This returns a new future, since we must stream body. +//! res.into_body().concat2() +//! }) +//! +//! // And then, if reading the full body succeeds... +//! .and_then(|body| { +//! // The body is just bytes, but let's print a string... +//! let s = ::std::str::from_utf8(&body) +//! .expect("httpbin sends utf-8 JSON"); +//! +//! println!("body: {}", s); +//! +//! // and_then requires we return a new Future, and it turns +//! // out that Result is a Future that is ready immediately. +//! Ok(()) +//! }) +//! +//! // Map any errors that might have happened... +//! .map_err(|err| { +//! println!("error: {}", err); +//! }) +//! })); +//! } +//! # #[cfg(not(feature = "runtime"))] +//! # fn main () {} +//! ``` use std::fmt; use std::io; @@ -14,13 +86,11 @@ use http::uri::Scheme; use body::{Body, Payload}; use common::Exec; +use self::connect::{Connect, Destination}; use self::pool::{Pool, Poolable, Reservation}; -pub use self::connect::Connect; #[cfg(feature = "runtime")] pub use self::connect::HttpConnector; -use self::connect::Destination; - pub mod conn; pub mod connect; pub(crate) mod dispatch; @@ -44,6 +114,11 @@ pub struct Client { #[cfg(feature = "runtime")] impl Client { /// Create a new Client with the default config. + /// + /// # Note + /// + /// The default connector does **not** handle TLS. Speaking to `https` + /// destinations will require configuring a connector that implements TLS. #[inline] pub fn new() -> Client { Builder::default().build_http() diff --git a/tests/support/mod.rs b/tests/support/mod.rs index 17650fcb..683299e6 100644 --- a/tests/support/mod.rs +++ b/tests/support/mod.rs @@ -189,7 +189,7 @@ pub struct __TestConfig { pub fn __run_test(cfg: __TestConfig) { extern crate pretty_env_logger; - use hyper::{Body, Client, Request, Response}; + use hyper::{Body, Client, Request, Response, Version}; use hyper::client::HttpConnector; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -197,6 +197,14 @@ pub fn __run_test(cfg: __TestConfig) { let rt = Runtime::new().expect("new rt"); let handle = rt.reactor().clone(); + assert_eq!(cfg.client_version, cfg.server_version); + + let version = if cfg.client_version == 2 { + Version::HTTP_2 + } else { + Version::HTTP_11 + }; + let connector = HttpConnector::new_with_handle(1, handle.clone()); let client = Client::builder() .keep_alive_timeout(Duration::from_secs(10)) @@ -217,6 +225,7 @@ pub fn __run_test(cfg: __TestConfig) { assert_eq!(req.uri().path(), sreq.uri); assert_eq!(req.method(), &sreq.method); + assert_eq!(req.version(), version); for (name, value) in &sreq.headers { assert_eq!( req.headers()[name], @@ -275,6 +284,7 @@ pub fn __run_test(cfg: __TestConfig) { rt.executor().spawn(server); + let make_request = Arc::new(move |client: &Client, creq: __CReq, cres: __CRes| { let uri = format!("http://{}{}", addr, creq.uri); let mut req = Request::builder() @@ -291,7 +301,7 @@ pub fn __run_test(cfg: __TestConfig) { client.request(req) .and_then(move |res| { assert_eq!(res.status(), cstatus); - //assert_eq!(res.version(), c_version); + assert_eq!(res.version(), version); for (name, value) in &cheaders { assert_eq!( res.headers()[name],