1#[cfg(feature = "use-hyper")]
2extern crate hyper;
3
4use std::io;
9use std::collections::BTreeMap;
10
11
12pub type Headers = BTreeMap<String, Vec<String>>;
14pub type Query<'s> = Vec<(String, String)>;
16
17pub enum Method {
20 Get,
21 Head,
22 Post,
23 Put,
24 Delete,
25 Patch,
26 Options,
27 Trace,
28 Connect,
29 Custom(String),
30}
31
32impl ToString for Method {
33 fn to_string(&self) -> String {
35 match *self {
36 Method::Get => "GET".to_string(),
37 Method::Head => "HEAD".to_string(),
38 Method::Post => "POST".to_string(),
39 Method::Put => "PUT".to_string(),
40 Method::Delete => "DELETE".to_string(),
41 Method::Patch => "PATCH".to_string(),
42 Method::Options => "OPTIONS".to_string(),
43 Method::Trace => "TRACE".to_string(),
44 Method::Connect => "CONNECT".to_string(),
45 Method::Custom(ref s) => s.clone(),
46 }
47 }
48}
49
50#[cfg(feature = "use-hyper")]
51impl From<hyper::method::Method> for Method {
52 fn from(m: hyper::method::Method) -> Method {
53 match m {
54 hyper::method::Method::Get => Method::Get,
55 hyper::method::Method::Head => Method::Head,
56 hyper::method::Method::Post => Method::Post,
57 hyper::method::Method::Put => Method::Put,
58 hyper::method::Method::Delete => Method::Delete,
59 hyper::method::Method::Patch => Method::Patch,
60 hyper::method::Method::Options => Method::Options,
61 hyper::method::Method::Trace => Method::Trace,
62 hyper::method::Method::Connect => Method::Connect,
63 hyper::method::Method::Extension(ref s) => Method::Custom(s.clone()),
64 }
65 }
66}
67
68#[cfg(feature = "use-hyper")]
69impl Into<hyper::method::Method> for Method {
70 fn into(self) -> hyper::method::Method {
71 match self {
72 Method::Get => hyper::method::Method::Get,
73 Method::Head => hyper::method::Method::Head,
74 Method::Post => hyper::method::Method::Post,
75 Method::Put => hyper::method::Method::Put,
76 Method::Delete => hyper::method::Method::Delete,
77 Method::Patch => hyper::method::Method::Patch,
78 Method::Options => hyper::method::Method::Options,
79 Method::Trace => hyper::method::Method::Trace,
80 Method::Connect => hyper::method::Method::Connect,
81 Method::Custom(s) => hyper::method::Method::Extension(s),
82 }
83 }
84}
85
86
87pub trait HttpResponse {
90 type Body: io::Read;
91
92 fn status(&self) -> u16;
95
96 fn reason(&self) -> &str;
99
100 fn headers(&self) -> Headers;
104
105 fn body(&mut self) -> &mut Self::Body;
107
108 fn is_1xx(&self) -> bool {
110 self.status() / 100 == 1
111 }
112
113 fn is_2xx(&self) -> bool {
115 self.status() / 100 == 2
116 }
117
118 fn is_3xx(&self) -> bool {
120 self.status() / 100 == 3
121 }
122
123 fn is_4xx(&self) -> bool {
125 self.status() / 100 == 4
126 }
127
128 fn is_5xx(&self) -> bool {
130 self.status() / 100 == 5
131 }
132}
133
134
135#[cfg(feature = "use-hyper")]
136impl HttpResponse for hyper::client::Response {
137 type Body = hyper::client::Response;
138
139 fn status(&self) -> u16 {
140 self.status.to_u16()
141 }
142
143 fn reason(&self) -> &str {
144 self.status_raw().1.as_ref()
145 }
146
147 fn headers(&self) -> Headers {
148 Headers::new()
149 }
150
151 fn body(&mut self) -> &mut hyper::client::Response {
152 return self
153 }
154}
155
156pub trait Api {
159 type Reply;
160 type Body: io::Read;
161 type Error;
162
163 fn method(&self) -> Method;
165
166 fn path(&self) -> String;
168
169 fn query(&self) -> Query;
171
172 fn headers(&self) -> Headers;
174
175 fn body(&self) -> Self::Body;
179
180 fn parse<Resp>(&self, &mut Resp) -> Result<Self::Reply, Self::Error> where Resp: HttpResponse;
183}
184
185
186#[derive(Debug)]
187pub enum SendError<S, A> {
188 Client(S),
189 Api(A)
190}
191
192pub trait Client<A: Api, E> {
193 fn send(&mut self, url: &str, req: A) -> Result<A::Reply, SendError<E, A::Error>>;
194}
195
196
197#[cfg(feature = "use-hyper")]
198impl<A: Api> Client<A, hyper::Error> for hyper::Client {
199 fn send(&mut self, url: &str, req: A)
203 -> Result<A::Reply, SendError<hyper::Error, A::Error>>
204 {
205 let mut url = hyper::Url::parse(url)
206 .map_err(|e| SendError::Client(hyper::Error::Uri(e)))?
207 .join(req.path().as_ref())
208 .map_err(|e| SendError::Client(hyper::Error::Uri(e)))?;
209 let mut body = req.body();
210 let body = hyper::client::Body::ChunkedBody(&mut body);
211
212 {
213 let mut query = url.query_pairs_mut();
214 for (name, value) in req.query() {
215 query.append_pair(name.as_str(), value.as_str());
216 }
217 }
218
219 let mut headers = hyper::header::Headers::new();
220 for (name, value) in req.headers() {
221 headers.set_raw(
222 name,
223 value.iter().map(|v| v.clone().into_bytes()).collect()
224 );
225 }
226
227 let mut resp = self.request(req.method().into(), url)
228 .headers(headers)
229 .body(body)
230 .send()
231 .map_err(|e| SendError::Client(e))?;
232
233 req.parse(&mut resp)
234 .map_err(|e| SendError::Api(e))
235 }
236}
237