use axum::{
extract::{Request, State},
response::Response,
body::Body,
};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use crate::http_server::WebServerState;
use crate::runtime::engine::Runtime;
use crate::http_server_middleware::{execute_middleware_chain, execute_route_handler};
use crate::http_server_converters::{axum_request_to_http_request, http_response_to_axum_response, error_response};
pub async fn handle_with_middleware(
State(state): State<Arc<RwLock<WebServerState>>>,
request: Request,
handler_name: &str,
) -> Response<Body> {
let mut http_request = axum_request_to_http_request(request).await;
let state_guard = state.read().await;
if let Some((_, params)) = get_route_handler_name_and_params(
&state_guard.server,
&http_request.method,
&http_request.path,
) {
http_request.path_params = params;
}
let middleware_list = &state_guard.server.middleware;
let mut runtime = if let Some(ref factory) = state_guard.runtime_factory {
factory()
} else {
Runtime::new()
};
let processed_request = match execute_middleware_chain(
&mut runtime,
middleware_list,
http_request,
) {
Ok(req) => req,
Err(e) => {
return error_response(403, &format!("Middleware error: {}", e));
}
};
let response = match execute_route_handler(
&mut runtime,
handler_name,
processed_request,
) {
Ok(resp) => resp,
Err(e) => {
return error_response(500, &format!("Handler error: {}", e));
}
};
http_response_to_axum_response(response)
}
fn path_pattern_matches(pattern: &str, path: &str) -> bool {
let pattern_segments: Vec<&str> = pattern.split('/').filter(|s| !s.is_empty()).collect();
let path_segments: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
if pattern_segments.len() != path_segments.len() {
return false;
}
for (p, v) in pattern_segments.iter().zip(path_segments.iter()) {
if !(*p == *v || (p.starts_with(':') && !v.is_empty())) {
return false;
}
}
true
}
fn path_params_from_match(pattern: &str, path: &str) -> Option<HashMap<String, String>> {
let pattern_segments: Vec<&str> = pattern.split('/').filter(|s| !s.is_empty()).collect();
let path_segments: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
if pattern_segments.len() != path_segments.len() {
return None;
}
let mut params = HashMap::new();
for (p, v) in pattern_segments.iter().zip(path_segments.iter()) {
if p.starts_with(':') && !v.is_empty() {
let param_name = p.trim_start_matches(':');
params.insert(param_name.to_string(), (*v).to_string());
} else if *p != *v {
return None;
}
}
Some(params)
}
pub fn get_route_handler_name_and_params(
server: &crate::stdlib::web::HttpServer,
method: &str,
path: &str,
) -> Option<(String, HashMap<String, String>)> {
let method_upper = method.to_uppercase();
let route_key = format!("{}:{}", method_upper, path);
if let Some(route) = server.routes.get(&route_key) {
return Some((route.handler.clone(), HashMap::new()));
}
for (key, route) in &server.routes {
if let Some((route_method, route_path)) = key.split_once(':') {
if route_method.eq_ignore_ascii_case(method)
&& path_pattern_matches(route_path, path)
{
let params = path_params_from_match(route_path, path).unwrap_or_default();
return Some((route.handler.clone(), params));
}
}
}
None
}
pub fn get_route_handler_name(
server: &crate::stdlib::web::HttpServer,
method: &str,
path: &str,
) -> Option<String> {
get_route_handler_name_and_params(server, method, path).map(|(name, _)| name)
}