use core::fmt;
use core::net::IpAddr;
use crate::forwarded::{self, parse_forwarded_for, parse_forwarded_for_rev, parse_x_forwarded_for, parse_x_forwarded_for_rev};
use crate::filter::Filter;
use crate::shared::FALLBACK_STR;
pub use http as http_ext;
use http_ext::header::FORWARDED;
const X_FORWARDED_FOR: http_ext::header::HeaderName = http_ext::header::HeaderName::from_static("x-forwarded-for");
pub struct HeaderValueFmt<'a>(http_ext::header::GetAll<'a, http_ext::header::HeaderValue>);
impl fmt::Debug for HeaderValueFmt<'_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut out = fmt.debug_list();
for header in self.0.iter() {
match header.to_str() {
Ok(header) => out.entry(&header),
Err(_) => out.entry(header),
};
}
out.finish()
}
}
impl fmt::Display for HeaderValueFmt<'_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut headers = self.0.iter();
if let Some(header) = headers.next() {
match header.to_str() {
Ok(header) => fmt.write_str(header)?,
Err(_) => fmt.write_str(FALLBACK_STR)?,
}
for header in headers {
fmt.write_str(" ,")?;
match header.to_str() {
Ok(header) => fmt.write_str(header)?,
Err(_) => fmt.write_str(FALLBACK_STR)?,
}
}
}
Ok(())
}
}
pub trait HeaderMapClientIp {
fn get_header_value_fmt(&self, key: impl http_ext::header::AsHeaderName) -> HeaderValueFmt<'_>;
fn extract_leftmost_forwarded_ip(&self) -> Option<IpAddr>;
fn extract_rightmost_forwarded_ip(&self) -> Option<IpAddr>;
fn extract_filtered_forwarded_ip(&self, filter: &impl Filter) -> Option<IpAddr>;
fn extract_filtered_forwarded_ip_after(&self, skip: usize, filter: &impl Filter) -> Option<IpAddr>;
}
impl HeaderMapClientIp for http_ext::HeaderMap {
#[inline(always)]
fn get_header_value_fmt(&self, key: impl http_ext::header::AsHeaderName) -> HeaderValueFmt<'_> {
HeaderValueFmt(self.get_all(key))
}
#[inline(always)]
fn extract_leftmost_forwarded_ip(&self) -> Option<IpAddr> {
crate::shared::impl_extract_leftmost_forwarded_ip!(self)
}
#[inline(always)]
fn extract_rightmost_forwarded_ip(&self) -> Option<IpAddr> {
crate::shared::impl_extract_rightmost_forwarded_ip!(self)
}
#[inline(always)]
fn extract_filtered_forwarded_ip(&self, filter: &impl Filter) -> Option<IpAddr> {
self.extract_filtered_forwarded_ip_after(0, filter)
}
fn extract_filtered_forwarded_ip_after(&self, skip: usize, filter: &impl Filter) -> Option<IpAddr> {
crate::shared::impl_extract_filtered_forwarded_ip!(self, filter, skip)
}
}