use axum::extract::{Request, State};
use axum::middleware::Next;
use axum::response::Response;
use crate::request_context::{
MAX_CHANGE_CONTEXT_LEN, MAX_REQUEST_ID_LEN, MAX_USER_AGENT_LEN, REQUEST_CONTEXT, RequestContext,
};
use crate::server::state::AppState;
const USER_AGENT: &str = "user-agent";
const CHANGE_CONTEXT: &str = "x-orion-change-context";
fn ascii_header(req: &Request, name: &str, max_len: usize) -> Option<String> {
req.headers()
.get(name)
.and_then(|v| v.to_str().ok())
.filter(|v| !v.is_empty())
.map(|v| v[..v.len().min(max_len)].to_string())
}
pub async fn request_context_scope(
State(state): State<AppState>,
req: Request,
next: Next,
) -> Response {
let request_id = req
.headers()
.get("x-request-id")
.and_then(|v| v.to_str().ok())
.map(|v| &v[..v.len().min(MAX_REQUEST_ID_LEN)])
.unwrap_or("")
.to_string();
let user_agent = ascii_header(&req, USER_AGENT, MAX_USER_AGENT_LEN);
let change_context = ascii_header(&req, CHANGE_CONTEXT, MAX_CHANGE_CONTEXT_LEN);
let client_ip = crate::server::rate_limit::extract_client_ip(&req, state.trusted_proxies());
let ctx = RequestContext {
request_id,
client_ip,
user_agent,
change_context,
};
REQUEST_CONTEXT.scope(ctx, next.run(req)).await
}