1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! The client portion of `tower-hyper`.
//!
//! The client module contains three main utiliteies client, connection
//! and connect. Connection and Connect are designed to be used together
//! where as Client is a thicker client designed to be used by itself. There
//! is less control over driving the inner service compared to Connection. The
//! other difference is that Connection is a lower level connection, so there is no
//! connection pooling etc, that is the job of the services that wrap it.
//!
//! # Client Usage
//!
//! [`Connect`] and [`Connection`] is a lower level connection based client. This means that
//! [`Connect`] provides a [`MakeService`] interface that produces [`Connection`]'s. This
//! is designed to be used in conjunction with [`tower-http`] and its set of utilities. [`Connect`]
//! takes a [`MakeConnection`] that is used to provide the underlying transport. This allows one
//! to create a TLS secured transport for example or use udp.
//!
//! [`Client`] just wraps hyper's [`hyper::Client`] and provides a simple [`Service`] interface.
//!
//! [`Connect`]: ./struct.Connect.html
//! [`Connection`]: ./struct.Connection.html
//! [`MakeService`]: ../../tower-util/trait.MakeService.html
//! [`Serivce`]: ../../tower_service/trait.Service.html
//! [`tower-http`]: https://github.com/tower-rs/tower-http
//! [`Client`]: ./struct.Client.html
//! [`hyper::Client`]: ../../hyper/struct.Client.html

mod connect;
mod connection;
mod future;

pub use self::connect::{Connect, ConnectError};
pub use self::connection::Connection;
use self::future::ResponseFuture;
pub use hyper::client::conn::Builder;

use crate::body::{Body, LiftBody};
use futures::{Async, Poll};
use http_body::Body as HttpBody;
use hyper::{
    client::connect::Connect as HyperConnect,
    client::{self, HttpConnector},
    Request, Response,
};
use tower_service::Service;

/// The client wrapp for `hyper::Client`
///
/// The generics `C` and `B` are 1-1 with the generic
/// types within `hyper::Client`.
#[derive(Clone, Debug)]
pub struct Client<C, B> {
    inner: hyper::Client<C, LiftBody<B>>,
}

impl<B> Client<HttpConnector, B>
where
    B: HttpBody + Send + 'static,
    B::Data: Send,
    B::Error: Into<crate::Error>,
{
    /// Create a new client, using the default hyper settings
    pub fn new() -> Self {
        let inner = hyper::Client::builder().build_http();
        Client { inner }
    }
}

impl<C, B> Client<C, B> {
    /// Create a new client by providing the inner `hyper::Client`
    ///
    /// ## Example
    ///
    /// The existing default is:
    ///```
    ///   use http::Request;
    ///   use tower_hyper::client::Client;
    ///   use tower_service::Service;
    ///
    ///   let inner = hyper::Client::builder().build_http();
    ///   let mut client = Client::with_client(inner);
    ///   let _ = client.call(Request::new(vec![0, 1, 2]));
    /// ````
    /// which returns a `Client<HttpConnector, B>` for any B: `HttpBody`.
    pub fn with_client(inner: hyper::Client<C, LiftBody<B>>) -> Self {
        Self { inner }
    }
}

impl<C, B> Service<Request<B>> for Client<C, B>
where
    C: HyperConnect + Sync + 'static,
    C::Transport: 'static,
    C::Future: 'static,
    B: HttpBody + Send + 'static,
    B::Data: Send,
    B::Error: Into<crate::Error>,
{
    type Response = Response<Body>;
    type Error = hyper::Error;
    type Future = ResponseFuture<client::ResponseFuture>;

    /// Poll to see if the service is ready, since `hyper::Client`
    /// already handles this internally this will always return ready
    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        Ok(Async::Ready(()))
    }

    /// Send the sepcficied request to the inner `hyper::Client`
    fn call(&mut self, req: Request<B>) -> Self::Future {
        let inner = self.inner.request(req.map(LiftBody::from));
        ResponseFuture { inner }
    }
}