use self::get::Get;
use self::payload_builder::PayloadBuilder;
use self::response_future::ResponseFuture;
use failure::Error;
use futures::future;
use http;
use hyper::{self, rt::Future};
use hyper_tls;
use native_tls;
use std::collections::HashMap;
use std::default::Default;
use std::error;
pub mod get;
pub mod payload_builder;
pub mod response_future;
type HttpClient<C> = hyper::Client<C, hyper::Body>;
type Url = str;
pub type HttpsClient = HttpClient<hyper_tls::HttpsConnector<hyper::client::HttpConnector>>;
const PKG_VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
const PKG_NAME: Option<&'static str> = option_env!("CARGO_PKG_NAME");
impl Default for HttperClient {
fn default() -> Self {
let http_client: hyper::Client<
hyper_tls::HttpsConnector<hyper::client::HttpConnector>,
_,
> = build_https_client().expect("Failed to build HTTPs client");
let mut headers = HashMap::new();
headers.insert(
hyper::header::USER_AGENT.as_str().to_string(),
format!(
"{}/{}",
PKG_NAME.unwrap_or("unknown_name"),
PKG_VERSION.unwrap_or("unknown_version"),
),
);
HttperClient {
http_client,
headers,
}
}
}
pub type Headers = HashMap<String, String>;
#[derive(Debug, Clone)]
pub struct HttperClient {
http_client: HttpsClient,
headers: Headers,
}
impl HttperClient {
pub fn new() -> Self {
HttperClient {
..HttperClient::default()
}
}
pub fn get(&self, url: &Url) -> Get {
Get::new(self.request_builder(url, hyper::Method::GET), &self)
}
pub fn post(&self, url: &Url) -> PayloadBuilder {
PayloadBuilder::new(self.request_builder(url, hyper::Method::POST), &self)
}
pub fn delete(&self, url: &Url) -> PayloadBuilder {
PayloadBuilder::new(self.request_builder(url, hyper::Method::DELETE), &self)
}
pub fn put(&self, url: &Url) -> PayloadBuilder {
PayloadBuilder::new(self.request_builder(url, hyper::Method::PUT), &self)
}
pub fn patch(&self, url: &Url) -> PayloadBuilder {
PayloadBuilder::new(self.request_builder(url, hyper::Method::PATCH), &self)
}
fn request_builder(
&self,
url: &Url,
method: hyper::Method,
) -> Result<http::request::Builder, Error> {
let url = self.parse_url(url)?;
let mut builder = http::request::Builder::new();
builder.method(method).uri(url);
Ok(builder)
}
fn send_request(
&self,
request_builder: Result<http::request::Builder, Error>,
payload: hyper::Body,
headers: Headers,
) -> ResponseFuture {
let headers = headers
.iter()
.map(|(key, value)| (key.to_lowercase(), value.to_string()));
let headers: Headers = self.headers.clone().into_iter().chain(headers).collect();
let http_client = self.http_client.clone();
ResponseFuture(Box::new(
future::result(request_builder.and_then(|mut request_builder| {
headers.iter().for_each(|(k, v)| {
request_builder.header(k.as_str(), v.as_str());
});
request_builder.body(payload).map_err(Error::from)
})).and_then(move |request| http_client.request(request).map_err(Error::from)),
))
}
fn parse_url(&self, url: &str) -> Result<hyper::Uri, Error> {
url.parse::<hyper::Uri>().map_err(Error::from)
}
}
fn build_https_client() -> Result<
hyper::client::Client<hyper_tls::HttpsConnector<hyper::client::HttpConnector>, hyper::Body>,
Box<error::Error>,
> {
let tls_connector = native_tls::TlsConnector::builder().build()?;
let mut http_connector = hyper::client::HttpConnector::new(4);
http_connector.enforce_http(false);
let https_connector = hyper_tls::HttpsConnector::from((http_connector, tls_connector));
let client = hyper::client::Client::builder().build(https_connector);
Ok(client)
}