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}