#[cfg(feature = "use-hyper")]
extern crate hyper;
use std::io;
use std::collections::BTreeMap;
pub type Headers = BTreeMap<String, Vec<String>>;
pub type Query<'s> = Vec<(String, String)>;
pub enum Method {
Get,
Head,
Post,
Put,
Delete,
Patch,
Options,
Trace,
Connect,
Custom(String),
}
impl ToString for Method {
fn to_string(&self) -> String {
match *self {
Method::Get => "GET".to_string(),
Method::Head => "HEAD".to_string(),
Method::Post => "POST".to_string(),
Method::Put => "PUT".to_string(),
Method::Delete => "DELETE".to_string(),
Method::Patch => "PATCH".to_string(),
Method::Options => "OPTIONS".to_string(),
Method::Trace => "TRACE".to_string(),
Method::Connect => "CONNECT".to_string(),
Method::Custom(ref s) => s.clone(),
}
}
}
#[cfg(feature = "use-hyper")]
impl From<hyper::method::Method> for Method {
fn from(m: hyper::method::Method) -> Method {
match m {
hyper::method::Method::Get => Method::Get,
hyper::method::Method::Head => Method::Head,
hyper::method::Method::Post => Method::Post,
hyper::method::Method::Put => Method::Put,
hyper::method::Method::Delete => Method::Delete,
hyper::method::Method::Patch => Method::Patch,
hyper::method::Method::Options => Method::Options,
hyper::method::Method::Trace => Method::Trace,
hyper::method::Method::Connect => Method::Connect,
hyper::method::Method::Extension(ref s) => Method::Custom(s.clone()),
}
}
}
#[cfg(feature = "use-hyper")]
impl Into<hyper::method::Method> for Method {
fn into(self) -> hyper::method::Method {
match self {
Method::Get => hyper::method::Method::Get,
Method::Head => hyper::method::Method::Head,
Method::Post => hyper::method::Method::Post,
Method::Put => hyper::method::Method::Put,
Method::Delete => hyper::method::Method::Delete,
Method::Patch => hyper::method::Method::Patch,
Method::Options => hyper::method::Method::Options,
Method::Trace => hyper::method::Method::Trace,
Method::Connect => hyper::method::Method::Connect,
Method::Custom(s) => hyper::method::Method::Extension(s),
}
}
}
pub trait HttpResponse {
type Body: io::Read;
fn status(&self) -> u16;
fn reason(&self) -> &str;
fn headers(&self) -> Headers;
fn body(&mut self) -> &mut Self::Body;
fn is_1xx(&self) -> bool {
self.status() / 100 == 1
}
fn is_2xx(&self) -> bool {
self.status() / 100 == 2
}
fn is_3xx(&self) -> bool {
self.status() / 100 == 3
}
fn is_4xx(&self) -> bool {
self.status() / 100 == 4
}
fn is_5xx(&self) -> bool {
self.status() / 100 == 5
}
}
#[cfg(feature = "use-hyper")]
impl HttpResponse for hyper::client::Response {
type Body = hyper::client::Response;
fn status(&self) -> u16 {
self.status.to_u16()
}
fn reason(&self) -> &str {
self.status_raw().1.as_ref()
}
fn headers(&self) -> Headers {
Headers::new()
}
fn body(&mut self) -> &mut hyper::client::Response {
return self
}
}
pub trait Api {
type Reply;
type Body: io::Read;
type Error;
fn method(&self) -> Method;
fn path(&self) -> String;
fn query(&self) -> Query;
fn headers(&self) -> Headers;
fn body(&self) -> Self::Body;
fn parse<Resp>(&self, &mut Resp) -> Result<Self::Reply, Self::Error> where Resp: HttpResponse;
}
#[derive(Debug)]
pub enum SendError<S, A> {
Client(S),
Api(A)
}
pub trait Client<A: Api, E> {
fn send(&mut self, url: &str, req: A) -> Result<A::Reply, SendError<E, A::Error>>;
}
#[cfg(feature = "use-hyper")]
impl<A: Api> Client<A, hyper::Error> for hyper::Client {
fn send(&mut self, url: &str, req: A)
-> Result<A::Reply, SendError<hyper::Error, A::Error>>
{
let mut url = hyper::Url::parse(url)
.map_err(|e| SendError::Client(hyper::Error::Uri(e)))?
.join(req.path().as_ref())
.map_err(|e| SendError::Client(hyper::Error::Uri(e)))?;
let mut body = req.body();
let body = hyper::client::Body::ChunkedBody(&mut body);
{
let mut query = url.query_pairs_mut();
for (name, value) in req.query() {
query.append_pair(name.as_str(), value.as_str());
}
}
let mut headers = hyper::header::Headers::new();
for (name, value) in req.headers() {
headers.set_raw(
name,
value.iter().map(|v| v.clone().into_bytes()).collect()
);
}
let mut resp = self.request(req.method().into(), url)
.headers(headers)
.body(body)
.send()
.map_err(|e| SendError::Client(e))?;
req.parse(&mut resp)
.map_err(|e| SendError::Api(e))
}
}