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
115
116
use crate::run::Seconds;
use crate::{Error, ErrorKind, Result};
use fibers_http_client::connection::ConnectionPoolHandle;
use fibers_http_client::Client;
use futures::Future;
use httpcodec::Response;
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::net::{SocketAddr, ToSocketAddrs};
use std::time::Duration;
use trackable::error::ErrorKindExt;
use url::Url;
use url_serde;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Request {
pub method: Method,
#[serde(with = "url_serde")]
pub url: Url,
pub content: Option<Content>,
pub timeout: Option<Seconds>,
pub start_time: Option<Seconds>,
}
impl Request {
pub fn addr(&self) -> Result<SocketAddr> {
let host = track!(self.url.host_str().ok_or_else(|| ErrorKind::Other.error()))?;
let port = self.url.port_or_known_default().expect("Never fails");
let mut addrs = track!(
(host, port).to_socket_addrs().map_err(Error::from),
"{}:{}",
host,
port
)?;
let addr = track_assert_some!(addrs.next(), ErrorKind::Other);
Ok(addr)
}
pub fn call(
&self,
client: &mut Client<ConnectionPoolHandle>,
timeout: Option<Duration>,
) -> Box<Future<Item = Response<Vec<u8>>, Error = Error> + Send + 'static> {
let mut request = client.request(&self.url);
if let Some(timeout) = timeout {
request = request.timeout(timeout);
}
match self.method {
Method::Get => Box::new(request.get().map_err(Error::from)),
Method::Head => Box::new(
request
.head()
.map(|res| res.map_body(|_| Vec::new()))
.map_err(Error::from),
),
Method::Delete => Box::new(request.delete().map_err(Error::from)),
Method::Post => {
let content = self.content.as_ref().map_or(Vec::new(), |c| c.to_bytes());
Box::new(request.post(content).map_err(Error::from))
}
Method::Put => {
let content = self.content.as_ref().map_or(Vec::new(), |c| c.to_bytes());
Box::new(request.put(content).map_err(Error::from))
}
}
}
pub fn path(&self) -> Cow<str> {
if self.url.query().is_none() && self.url.fragment().is_none() {
Cow::Borrowed(self.url.path())
} else {
let mut path = self.url.path().to_string();
if let Some(query) = self.url.query() {
path.push('?');
path.push_str(query);
}
if let Some(fragment) = self.url.fragment() {
path.push('#');
path.push_str(fragment);
}
Cow::Owned(path)
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum Method {
Put,
Post,
Get,
Head,
Delete,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Content {
Size(usize),
Text(String),
}
impl Content {
pub fn size(&self) -> usize {
match *self {
Content::Size(size) => size,
Content::Text(ref text) => text.len(),
}
}
pub fn to_bytes(&self) -> Vec<u8> {
match *self {
Content::Size(size) => vec![0; size],
Content::Text(ref text) => text.clone().into_bytes(),
}
}
}