1use core::fmt;
4use core::net::IpAddr;
5
6use crate::forwarded::{self, parse_forwarded_for, parse_forwarded_for_rev, parse_x_forwarded_for, parse_x_forwarded_for_rev};
7use crate::filter::Filter;
8use crate::shared::FALLBACK_STR;
9
10pub use http as http_ext;
12use http_ext::header::FORWARDED;
13const X_FORWARDED_FOR: http_ext::header::HeaderName = http_ext::header::HeaderName::from_static("x-forwarded-for");
14
15pub struct HeaderValueFmt<'a>(http_ext::header::GetAll<'a, http_ext::header::HeaderValue>);
17
18impl fmt::Debug for HeaderValueFmt<'_> {
19 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
20 let mut out = fmt.debug_list();
21 for header in self.0.iter() {
22 match header.to_str() {
23 Ok(header) => out.entry(&header),
24 Err(_) => out.entry(header),
25 };
26 }
27
28 out.finish()
29 }
30}
31
32impl fmt::Display for HeaderValueFmt<'_> {
33 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
34 let mut headers = self.0.iter();
35 if let Some(header) = headers.next() {
36 match header.to_str() {
37 Ok(header) => fmt.write_str(header)?,
38 Err(_) => fmt.write_str(FALLBACK_STR)?,
39 }
40
41 for header in headers {
42 fmt.write_str(" ,")?;
43 match header.to_str() {
44 Ok(header) => fmt.write_str(header)?,
45 Err(_) => fmt.write_str(FALLBACK_STR)?,
46 }
47 }
48 }
49
50 Ok(())
51 }
52}
53
54pub trait HeaderMapClientIp {
56 fn get_header_value_fmt(&self, key: impl http_ext::header::AsHeaderName) -> HeaderValueFmt<'_>;
58
59 fn extract_leftmost_forwarded_ip(&self) -> Option<IpAddr>;
66 fn extract_rightmost_forwarded_ip(&self) -> Option<IpAddr>;
70 fn extract_filtered_forwarded_ip(&self, filter: &impl Filter) -> Option<IpAddr>;
74 fn extract_filtered_forwarded_ip_after(&self, skip: usize, filter: &impl Filter) -> Option<IpAddr>;
78}
79
80impl HeaderMapClientIp for http_ext::HeaderMap {
81 #[inline(always)]
82 fn get_header_value_fmt(&self, key: impl http_ext::header::AsHeaderName) -> HeaderValueFmt<'_> {
83 HeaderValueFmt(self.get_all(key))
84 }
85
86 #[inline(always)]
87 fn extract_leftmost_forwarded_ip(&self) -> Option<IpAddr> {
88 crate::shared::impl_extract_leftmost_forwarded_ip!(self)
89 }
90
91 #[inline(always)]
92 fn extract_rightmost_forwarded_ip(&self) -> Option<IpAddr> {
93 crate::shared::impl_extract_rightmost_forwarded_ip!(self)
94 }
95
96 #[inline(always)]
97 fn extract_filtered_forwarded_ip(&self, filter: &impl Filter) -> Option<IpAddr> {
98 self.extract_filtered_forwarded_ip_after(0, filter)
99 }
100
101 fn extract_filtered_forwarded_ip_after(&self, skip: usize, filter: &impl Filter) -> Option<IpAddr> {
102 crate::shared::impl_extract_filtered_forwarded_ip!(self, filter, skip)
103 }
104}