micromegas/servers/
http_utils.rs

1//! HTTP utilities for server implementations
2
3/// Extracts the client IP address from HTTP headers and extensions.
4///
5/// This function checks headers in order of priority:
6/// 1. X-Forwarded-For (leftmost IP is the original client when behind proxies)
7/// 2. X-Real-IP (used by some proxies like nginx)
8/// 3. Socket address from extensions (direct connection)
9///
10/// Returns "unknown" if no IP can be extracted.
11pub fn get_client_ip(headers: &http::HeaderMap, extensions: &http::Extensions) -> String {
12    // Check X-Forwarded-For header first (for load balancers/proxies)
13    // The leftmost IP is the original client when behind proxies
14    if let Some(forwarded_for) = headers.get("x-forwarded-for")
15        && let Ok(value) = forwarded_for.to_str()
16        && let Some(client_ip) = value.split(',').next()
17    {
18        return client_ip.trim().to_string();
19    }
20
21    // Check X-Real-IP header (used by some proxies like nginx)
22    if let Some(real_ip) = headers.get("x-real-ip")
23        && let Ok(value) = real_ip.to_str()
24    {
25        return value.to_string();
26    }
27
28    // Fall back to socket address from extensions
29    // Axum provides ConnectInfo<SocketAddr>, Tonic provides SocketAddr directly
30    if let Some(connect_info) = extensions.get::<axum::extract::ConnectInfo<std::net::SocketAddr>>()
31    {
32        return connect_info.0.ip().to_string();
33    }
34
35    if let Some(remote_addr) = extensions.get::<std::net::SocketAddr>() {
36        return remote_addr.ip().to_string();
37    }
38
39    "unknown".to_string()
40}