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
|
use std::sync::Arc;
use anyhow::Result;
use log::*;
use http::uri::Authority;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, StatusCode, Uri};
use crate::consul::Consul;
const CHALLENGE_PREFIX: &str = "/.well-known/acme-challenge/";
async fn handle(req: Request<Body>, consul: Arc<Consul>) -> Result<Response<Body>> {
let path = req.uri().path();
info!("HTTP request {}", path);
if let Some(token) = path.strip_prefix(CHALLENGE_PREFIX) {
let response = consul.kv_get(&format!("challenge/{}", token)).await?;
match response {
Some(r) => Ok(Response::new(Body::from(r))),
None => Ok(Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::from(""))?),
}
} else {
// Redirect to HTTPS
let uri2 = req.uri().clone();
let mut parts = uri2.into_parts();
let host = req
.headers()
.get("Host")
.map(|h| h.to_str())
.ok_or_else(|| anyhow!("Missing host header"))??
.to_string();
parts.authority = Some(Authority::from_maybe_shared(host)?);
parts.scheme = Some("https".parse().unwrap());
let uri2 = Uri::from_parts(parts)?;
Ok(Response::builder()
.status(StatusCode::MOVED_PERMANENTLY)
.header("Location", uri2.to_string())
.body(Body::from(""))?)
}
}
pub async fn serve_http(consul: Consul) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let consul = Arc::new(consul);
// For every connection, we must make a `Service` to handle all
// incoming HTTP requests on said connection.
let make_svc = make_service_fn(|_conn| {
let consul = consul.clone();
// This is the `Service` that will handle the connection.
// `service_fn` is a helper to convert a function that
// returns a Response into a `Service`.
async move {
Ok::<_, anyhow::Error>(service_fn(move |req: Request<Body>| {
let consul = consul.clone();
handle(req, consul)
}))
}
});
let addr = ([0, 0, 0, 0], 1080).into();
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{}", addr);
server.await?;
Ok(())
}
|