1use core::fmt;
4use core::net::IpAddr;
5
6pub use tonic014 as tonic;
7pub use tonic::metadata::MetadataMap;
8
9use crate::forwarded::{self, parse_forwarded_for, parse_forwarded_for_rev, parse_x_forwarded_for, parse_x_forwarded_for_rev};
10use crate::filter::Filter;
11use crate::shared::FALLBACK_STR;
12
13const FORWARDED: &str = "forwarded";
14const X_FORWARDED_FOR: &str = "x-forwarded-for";
15
16pub struct MetadataValueFmt<'a>(tonic::metadata::GetAll<'a, tonic::metadata::Ascii>);
18
19impl fmt::Debug for MetadataValueFmt<'_> {
20 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
21 let mut out = fmt.debug_list();
22 for header in self.0.iter() {
23 match header.to_str() {
24 Ok(header) => out.entry(&header),
25 Err(_) => out.entry(header),
26 };
27 }
28
29 out.finish()
30 }
31}
32
33impl fmt::Display for MetadataValueFmt<'_> {
34 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
35 let mut headers = self.0.iter();
36 if let Some(header) = headers.next() {
37 match header.to_str() {
38 Ok(header) => fmt.write_str(header)?,
39 Err(_) => fmt.write_str(FALLBACK_STR)?,
40 }
41
42 for header in headers {
43 fmt.write_str(" ,")?;
44 match header.to_str() {
45 Ok(header) => fmt.write_str(header)?,
46 Err(_) => fmt.write_str(FALLBACK_STR)?,
47 }
48 }
49 }
50
51 Ok(())
52 }
53}
54
55pub trait MetadataMapClientIp {
57 fn get_header_value_fmt(&self, key: &str) -> MetadataValueFmt<'_>;
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 MetadataMapClientIp for MetadataMap {
81 #[inline(always)]
82 fn get_header_value_fmt(&self, key: &str) -> MetadataValueFmt<'_> {
83 MetadataValueFmt(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}