1use core::{fmt, marker};
3use core::net::IpAddr;
4
5use crate::find_next_ip_after_filter;
6use crate::filter::Filter;
7use crate::forwarded::parse_forwarded_for_rev;
8use ohkami024::{FromRequest, Request};
9
10#[repr(transparent)]
11#[derive(Copy, Clone)]
12pub struct ClientIp<F: Filter> {
16 pub inner: Option<IpAddr>,
18 _filter: marker::PhantomData<F>
19}
20
21impl<F: Filter> ClientIp<F> {
22 #[inline(always)]
23 fn new(inner: Option<IpAddr>) -> Self {
24 Self {
25 inner,
26 _filter: marker::PhantomData,
27 }
28 }
29
30 #[inline(always)]
31 pub fn into_inner(self) -> Option<IpAddr> {
33 self.inner
34 }
35}
36
37impl<F: Filter> fmt::Debug for ClientIp<F> {
38 #[inline(always)]
39 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
40 fmt::Debug::fmt(&self.inner, fmt)
41 }
42}
43
44impl<'req, F: Send + Sync + Filter + 'static> FromRequest<'req> for ClientIp<F> {
45 type Error = core::convert::Infallible;
47 fn from_request(req: &'req Request) -> Option<Result<Self, Self::Error>> {
51 let filter = req.context.get::<F>()?;
52 if let Some(ip) = req.headers.forwarded().and_then(|value| find_next_ip_after_filter(parse_forwarded_for_rev(value), filter)) {
54 Some(Ok(ClientIp::new(Some(ip))))
55 } else {
56 Some(Ok(ClientIp::new(None)))
58 }
59 }
60}