forked from Deuxfleurs/tricot
76 lines
2 KiB
Rust
76 lines
2 KiB
Rust
|
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(())
|
||
|
}
|