use std::collections::HashMap;
use std::sync::Arc;
use certon::Storage;
use certon::http_handler::HttpChallengeHandler;
use salvo::http::StatusCode;
use salvo::{Depot, FlowCtrl, Request, Response, async_trait};
use tracing::debug;
pub struct AcmeChallengeHoop {
handler: HttpChallengeHandler,
}
impl AcmeChallengeHoop {
pub fn new(
challenges: Arc<tokio::sync::RwLock<HashMap<String, String>>>,
storage: Option<Arc<dyn Storage>>,
) -> Self {
Self {
handler: HttpChallengeHandler::new(challenges, storage),
}
}
}
#[async_trait]
impl salvo::Handler for AcmeChallengeHoop {
async fn handle(
&self,
req: &mut Request,
depot: &mut Depot,
res: &mut Response,
ctrl: &mut FlowCtrl,
) {
let method = req.method().as_str().to_owned();
let uri = req.uri().clone();
let path = uri.path();
let host = req
.headers()
.get(http::header::HOST)
.and_then(|v| v.to_str().ok())
.unwrap_or("");
if let Some((status, body)) = self.handler.handle_http_request(&method, host, path).await {
let client_addr = super::client_addr(req);
debug!(
path = %path,
status = status,
client = %client_addr,
"served ACME HTTP-01 challenge response"
);
let http_status =
StatusCode::from_u16(status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
res.status_code(http_status);
let _ = res.add_header(http::header::CONTENT_TYPE, "text/plain", true);
res.body(body);
ctrl.skip_rest();
return;
}
ctrl.call_next(req, depot, res).await;
}
}