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
extern crate hyper;
extern crate reqwest;
extern crate tokio_threadpool;
use std::fs;
use std::io::ErrorKind;
use std::net::SocketAddr;
use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use hyper::rt::Future;
use hyper::service::service_fn_ok;
use hyper::{Body, Error, Method, Request, Response, Server, StatusCode};
use tokio_threadpool::ThreadPool;
pub struct Keyserver {
url: String,
_thread_pool: ThreadPool,
}
impl Keyserver {
pub fn start() -> Keyserver {
Keyserver::start_on_port(0)
}
pub fn start_on_port(port: u16) -> Keyserver {
let addr = ([127, 0, 0, 1], port).into();
let thread_pool = ThreadPool::new();
let (bound_addr, server) = server(&addr);
thread_pool.spawn(server.map_err(|e| eprintln!("server error: {}", e)));
let url = format!("http://localhost:{}/", bound_addr.port());
Keyserver {
url,
_thread_pool: thread_pool,
}
}
pub fn url(&self) -> &str {
&self.url
}
pub fn count(&self) -> String {
reqwest::get(&format!("{}count", self.url()))
.unwrap()
.text()
.unwrap()
}
}
pub fn server(addr: &SocketAddr) -> (SocketAddr, impl Future<Item = (), Error = Error>) {
let counter = Arc::new(AtomicUsize::new(0));
let new_service = move || {
let counter = counter.clone();
service_fn_ok(move |r| service(r, &counter))
};
let server = Server::bind(addr).serve(new_service);
let local_addr = server.local_addr();
(local_addr, server)
}
const KEYS_PATH: &'static str = "support/keys/";
fn service(request: Request<Body>, counter: &AtomicUsize) -> Response<Body> {
match (request.method(), request.uri().path()) {
(&Method::GET, "/count") => {
Response::new(Body::from(counter.load(Ordering::Relaxed).to_string()))
}
(&Method::GET, key_path) => {
let relative = Path::new(key_path).strip_prefix("/").unwrap();
match fs::read(&Path::new(KEYS_PATH).join(&relative)) {
Ok(content) => {
counter.fetch_add(1, Ordering::Relaxed);
Response::builder()
.header("Content-Type", "application/x-pem-file")
.body(Body::from(content))
.unwrap()
}
Err(e) => match e.kind() {
ErrorKind::NotFound => Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::empty())
.unwrap(),
_ => {
eprintln!("Error reading file with path {:?}: {}", &key_path, e);
Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::empty())
.unwrap()
}
},
}
}
_ => Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::empty())
.unwrap(),
}
}