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}
75
76impl MetadataMapClientIp for MetadataMap {
77 #[inline(always)]
78 fn get_header_value_fmt(&self, key: &str) -> MetadataValueFmt<'_> {
79 MetadataValueFmt(self.get_all(key))
80 }
81
82 #[inline(always)]
83 fn extract_leftmost_forwarded_ip(&self) -> Option<IpAddr> {
84 crate::shared::impl_extract_leftmost_forwarded_ip!(self)
85 }
86
87 #[inline(always)]
88 fn extract_rightmost_forwarded_ip(&self) -> Option<IpAddr> {
89 crate::shared::impl_extract_rightmost_forwarded_ip!(self)
90 }
91
92 fn extract_filtered_forwarded_ip(&self, filter: &impl Filter) -> Option<IpAddr> {
93 crate::shared::impl_extract_filtered_forwarded_ip!(self, filter)
94 }
95}