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::{FangProc, Fang};
9use ohkami024::{FromRequest, Request, Response};
10
11#[repr(transparent)]
12#[derive(Copy, Clone)]
13pub struct ClientIp<F: Filter> {
17 pub inner: Option<IpAddr>,
19 _filter: marker::PhantomData<F>
20}
21
22impl<F: Filter> ClientIp<F> {
23 #[inline(always)]
24 fn new(inner: Option<IpAddr>) -> Self {
25 Self {
26 inner,
27 _filter: marker::PhantomData,
28 }
29 }
30
31 #[inline(always)]
32 pub fn into_inner(self) -> Option<IpAddr> {
34 self.inner
35 }
36}
37
38impl<F: Filter> fmt::Debug for ClientIp<F> {
39 #[inline(always)]
40 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
41 fmt::Debug::fmt(&self.inner, fmt)
42 }
43}
44
45impl<'req, F: Send + Sync + Filter + 'static> FromRequest<'req> for ClientIp<F> {
46 type Error = core::convert::Infallible;
48 fn from_request(req: &'req Request) -> Option<Result<Self, Self::Error>> {
52 let filter = req.context.get::<F>()?;
53 if let Some(ip) = req.headers.forwarded().and_then(|value| find_next_ip_after_filter(parse_forwarded_for_rev(value), filter)) {
55 Some(Ok(ClientIp::new(Some(ip))))
56 } else {
57 Some(Ok(ClientIp::new(None)))
59 }
60 }
61}
62
63#[derive(Clone)]
64pub struct ClientIpMiddleware<F> {
66 filter: F,
67}
68
69impl<F: Filter + Clone + 'static> ClientIpMiddleware<F> {
70 #[inline(always)]
71 pub const fn new(filter: F) -> Self {
73 Self {
74 filter
75 }
76 }
77}
78
79impl<F: Filter + Clone + 'static, I: FangProc> Fang<I> for ClientIpMiddleware<F> {
80 type Proc = ClientIpMiddlewareProc<I, F>;
81 #[inline(always)]
82 fn chain(&self, inner: I) -> Self::Proc {
83 ClientIpMiddlewareProc {
84 inner,
85 filter: self.filter.clone(),
86 }
87 }
88}
89
90pub struct ClientIpMiddlewareProc<I, F> {
92 inner: I,
93 filter: F,
94}
95
96impl<I: FangProc, F: Filter + 'static> FangProc for ClientIpMiddlewareProc<I, F> {
97 #[inline(always)]
98 fn bite<'b>(&'b self, req: &'b mut Request) -> impl Future<Output = Response> {
99 if req.ip.is_unspecified() {
100 if let Some(ip) = req.headers.forwarded().and_then(|value| find_next_ip_after_filter(parse_forwarded_for_rev(value), &self.filter)) {
102 req.ip = ip;
103 }
104 }
105
106 self.inner.bite(req)
107 }
108}