use core::{fmt, marker};
use core::net::{IpAddr, SocketAddr};
pub use axum08::*;
use axum08::extract::FromRequestParts;
use crate::filter::Filter;
use crate::http::HeaderMapClientIp;
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct ClientIp<F: Filter> {
pub inner: Option<IpAddr>,
_filter: marker::PhantomData<F>
}
impl<F: Filter> ClientIp<F> {
#[inline(always)]
fn new(inner: Option<IpAddr>) -> Self {
Self {
inner,
_filter: marker::PhantomData,
}
}
#[inline(always)]
pub fn into_inner(self) -> Option<IpAddr> {
self.inner
}
}
impl<F: Filter> fmt::Debug for ClientIp<F> {
#[inline(always)]
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.inner, fmt)
}
}
impl<S: Send + Sync, F: Send + Sync + Filter + Clone + extract::FromRef<S>> FromRequestParts<S> for ClientIp<F> {
type Rejection = core::convert::Infallible;
async fn from_request_parts(parts: &mut http::request::Parts, state: &S) -> Result<Self, Self::Rejection> {
let filter: F = extract::FromRef::from_ref(state);
let ip = if let Some(ip) = parts.headers.extract_filtered_forwarded_ip(&filter) {
Some(ip)
} else if let Ok(addr) = extract::ConnectInfo::<SocketAddr>::from_request_parts(parts, state).await {
Some(addr.ip())
} else {
None
};
Ok(ClientIp::new(ip))
}
}