use std::io;
use std::net::{TcpStream, ToSocketAddrs};
use std::time::Duration;
use hyper::error::Result;
use hyper::net::{HttpStream, HttpsStream, NetworkConnector, SslClient};
pub struct ClickSslConnector<S: SslClient> {
ssl: S,
host_addr: Option<(String, String)>,
connect_timeout: Duration,
}
impl<S: SslClient> ClickSslConnector<S> {
pub fn new(
s: S,
host_addr: Option<(String, String)>,
connect_timeout: Duration,
) -> ClickSslConnector<S> {
ClickSslConnector {
ssl: s,
host_addr,
connect_timeout,
}
}
pub fn copy(&self, ssl: S) -> ClickSslConnector<S> {
ClickSslConnector {
ssl,
host_addr: self.host_addr.clone(),
connect_timeout: self.connect_timeout,
}
}
fn click_connect(&self, host: &str, port: u16, scheme: &str) -> Result<HttpStream> {
let addr = match self.host_addr {
Some((ref target_host, ref ip)) => {
if host == target_host {
(ip.as_str(), port)
} else {
(host, port)
}
}
None => (host, port),
};
let addrs = addr.to_socket_addrs()?;
let mut last_err = io::Error::new(io::ErrorKind::InvalidInput, "Invalid scheme for Http");
match scheme {
"http" => {
for addr in addrs {
match TcpStream::connect_timeout(&addr, self.connect_timeout) {
Ok(stream) => return Ok(HttpStream(stream)),
Err(e) => last_err = e,
}
}
Err(last_err.into())
}
_ => Err(last_err.into()),
}
}
}
impl<S: SslClient> NetworkConnector for ClickSslConnector<S> {
type Stream = HttpsStream<S::Stream>;
fn connect(&self, host: &str, port: u16, scheme: &str) -> Result<Self::Stream> {
let stream = self.click_connect(host, port, "http")?;
if scheme == "https" {
self.ssl.wrap_client(stream, host).map(HttpsStream::Https)
} else {
Ok(HttpsStream::Http(stream))
}
}
}