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
117
118
119
120
121
122
123
124
use futures::stream::Stream;
use futures::{future, Future};
use hyper::service::{NewService, Service};
use hyper::{Body, Error, Request, Response, StatusCode};
use super::Constructor;
use super::ContentType;
use super::Delivery;
use super::Handler;
macro_rules! hyper_get_header_value {
($headers:expr, $key:expr) => {
if let Some(value) = $headers.get($key) {
if let Ok(inner) = value.to_str() {
Some(String::from(inner.clone()))
} else {
None
}
} else {
None
}
};
}
impl NewService for Constructor {
type ReqBody = Body;
type ResBody = Body;
type Error = Error;
type Service = Handler;
type Future = Box<Future<Item = Self::Service, Error = Self::InitError> + Send>;
type InitError = Error;
fn new_service(&self) -> Self::Future {
debug!("Creating new service");
Box::new(future::ok(Handler::from(self)))
}
}
impl Service for Handler {
type ReqBody = Body;
type ResBody = Body;
type Error = Error;
type Future = Box<Future<Item = Response<Body>, Error = Error> + Send + 'static>;
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
fn response(status_code: StatusCode, body: &'static str) -> Response<Body> {
Response::builder()
.status(status_code)
.body(body.into())
.unwrap()
}
let headers = req.headers();
let (event, executor) =
if let Some(event_string) = hyper_get_header_value!(&headers, "X-Github-Event") {
(
Some(event_string.clone()),
self.get_hooks(event_string.as_str()),
)
} else {
return Box::new(future::ok(response(
StatusCode::ACCEPTED,
"Invalid payload",
)));
};
if executor.is_empty() {
return Box::new(future::ok(response(
StatusCode::ACCEPTED,
"No matched hook configured",
)));
}
let id = hyper_get_header_value!(&headers, "X-Github-Delivery");
let signature = hyper_get_header_value!(&headers, "X-Hub-Signature");
let content_type = hyper_get_header_value!(&headers, "content-type");
if content_type.is_none() {
return Box::new(future::ok(response(
StatusCode::ACCEPTED,
"Invalid payload",
)));
}
Box::new(
req.into_body()
.concat2()
.map(move |chunk| String::from_utf8(chunk.to_vec()).ok())
.and_then(move |request_body| {
let content_type: ContentType = match content_type.unwrap().as_str() {
"application/x-www-form-urlencoded" => ContentType::URLENCODED,
_ => ContentType::JSON,
};
if request_body.is_some() {
let delivery =
Delivery::new(id, event, signature, content_type, request_body);
debug!("Received delivery: {:#?}", &delivery);
executor.run(delivery);
future::ok(response(StatusCode::OK, "OK"))
} else {
future::ok(response(StatusCode::ACCEPTED, "Invalid payload"))
}
}),
)
}
}