use crate::call_context::CallContext;
pub(super) fn caller_key(ctx: &CallContext, trusted_proxy_hops: usize) -> String {
if let Some(identity) = ctx.caller_identity() {
return identity.to_owned();
}
let hops = trusted_proxy_hops;
if hops > 0 {
if let Some(xff) = ctx.http_headers().get("x-forwarded-for") {
let entries: Vec<&str> = xff
.split(',')
.map(str::trim)
.filter(|e| !e.is_empty())
.collect();
if entries.len() >= hops {
return canonicalize_caller_ip(entries[entries.len() - hops]);
}
}
}
"anonymous".to_string()
}
pub(super) fn canonicalize_caller_ip(entry: &str) -> String {
use std::net::IpAddr;
let trimmed = entry.trim().trim_start_matches('[').trim_end_matches(']');
match trimmed.parse::<IpAddr>() {
Ok(IpAddr::V6(v6)) => v6
.to_ipv4_mapped()
.map_or_else(|| IpAddr::V6(v6).to_string(), |v4| v4.to_string()),
Ok(ip) => ip.to_string(),
Err(_) => trimmed.to_string(),
}
}