rama_http/headers/forwarded/
x_forwarded_for.rs1use crate::headers::{self, Header};
2use crate::{HeaderName, HeaderValue};
3use rama_net::forwarded::ForwardedElement;
4use std::iter::FromIterator;
5use std::net::IpAddr;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct XForwardedFor(Vec<IpAddr>);
27
28impl Header for XForwardedFor {
29 fn name() -> &'static HeaderName {
30 &crate::header::X_FORWARDED_FOR
31 }
32
33 fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(
34 values: &mut I,
35 ) -> Result<Self, headers::Error> {
36 crate::headers::util::csv::from_comma_delimited(values).map(XForwardedFor)
37 }
38
39 fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
40 use std::fmt;
41 struct Format<F>(F);
42 impl<F> fmt::Display for Format<F>
43 where
44 F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
45 {
46 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47 (self.0)(f)
48 }
49 }
50 let s = format!(
51 "{}",
52 Format(|f: &mut fmt::Formatter<'_>| {
53 crate::headers::util::csv::fmt_comma_delimited(&mut *f, self.0.iter())
54 })
55 );
56 values.extend(Some(HeaderValue::from_str(&s).unwrap()))
57 }
58}
59
60impl FromIterator<IpAddr> for XForwardedFor {
61 fn from_iter<T>(iter: T) -> Self
62 where
63 T: IntoIterator<Item = IpAddr>,
64 {
65 XForwardedFor(iter.into_iter().collect())
66 }
67}
68
69impl super::ForwardHeader for XForwardedFor {
70 fn try_from_forwarded<'a, I>(input: I) -> Option<Self>
71 where
72 I: IntoIterator<Item = &'a ForwardedElement>,
73 {
74 let vec: Vec<_> = input
75 .into_iter()
76 .filter_map(|el| el.ref_forwarded_for()?.ip())
77 .collect();
78 if vec.is_empty() {
79 None
80 } else {
81 Some(XForwardedFor(vec))
82 }
83 }
84}
85
86impl XForwardedFor {
87 pub fn iter(&self) -> impl Iterator<Item = &IpAddr> {
89 self.0.iter()
90 }
91}
92
93impl IntoIterator for XForwardedFor {
94 type Item = ForwardedElement;
95 type IntoIter = XForwardedForIterator;
96
97 fn into_iter(self) -> Self::IntoIter {
98 XForwardedForIterator(self.0.into_iter())
99 }
100}
101
102#[derive(Debug, Clone)]
103pub struct XForwardedForIterator(std::vec::IntoIter<IpAddr>);
105
106impl Iterator for XForwardedForIterator {
107 type Item = ForwardedElement;
108
109 fn next(&mut self) -> Option<Self::Item> {
110 self.0.next().map(ForwardedElement::forwarded_for)
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 use rama_http_types::HeaderValue;
119
120 macro_rules! test_header {
121 ($name: ident, $input: expr, $expected: expr) => {
122 #[test]
123 fn $name() {
124 assert_eq!(
125 XForwardedFor::decode(
126 &mut $input
127 .into_iter()
128 .map(|s| HeaderValue::from_bytes(s.as_bytes()).unwrap())
129 .collect::<Vec<_>>()
130 .iter()
131 )
132 .ok(),
133 $expected,
134 );
135 }
136 };
137 }
138
139 test_header!(
141 test1,
142 vec!["2001:db8:85a3:8d3:1319:8a2e:370:7348"],
143 Some(XForwardedFor(vec![
144 "2001:db8:85a3:8d3:1319:8a2e:370:7348".parse().unwrap(),
145 ]))
146 );
147 test_header!(
148 test2,
149 vec!["203.0.113.195"],
150 Some(XForwardedFor(vec!["203.0.113.195".parse().unwrap(),]))
151 );
152 test_header!(
153 test3,
154 vec!["203.0.113.195, 2001:db8:85a3:8d3:1319:8a2e:370:7348"],
155 Some(XForwardedFor(vec![
156 "203.0.113.195".parse().unwrap(),
157 "2001:db8:85a3:8d3:1319:8a2e:370:7348".parse().unwrap()
158 ]))
159 );
160 test_header!(
161 test4,
162 vec!["203.0.113.195", "2001:db8:85a3:8d3:1319:8a2e:370:7348"],
163 Some(XForwardedFor(vec![
164 "203.0.113.195".parse().unwrap(),
165 "2001:db8:85a3:8d3:1319:8a2e:370:7348".parse().unwrap()
166 ]))
167 );
168 test_header!(
169 test5,
170 vec![
171 "203.0.113.195,2001:db8:85a3:8d3:1319:8a2e:370:7348",
172 "198.51.100.178"
173 ],
174 Some(XForwardedFor(vec![
175 "203.0.113.195".parse().unwrap(),
176 "2001:db8:85a3:8d3:1319:8a2e:370:7348".parse().unwrap(),
177 "198.51.100.178".parse().unwrap()
178 ]))
179 );
180 test_header!(
181 test6,
182 vec![
183 "203.0.113.195",
184 "2001:db8:85a3:8d3:1319:8a2e:370:7348",
185 "198.51.100.178",
186 ],
187 Some(XForwardedFor(vec![
188 "203.0.113.195".parse().unwrap(),
189 "2001:db8:85a3:8d3:1319:8a2e:370:7348".parse().unwrap(),
190 "198.51.100.178".parse().unwrap()
191 ]))
192 );
193 test_header!(
194 test7,
195 vec![
196 "203.0.113.195",
197 "2001:db8:85a3:8d3:1319:8a2e:370:7348,198.51.100.178",
198 ],
199 Some(XForwardedFor(vec![
200 "203.0.113.195".parse().unwrap(),
201 "2001:db8:85a3:8d3:1319:8a2e:370:7348".parse().unwrap(),
202 "198.51.100.178".parse().unwrap()
203 ]))
204 );
205
206 #[test]
207 fn test_x_forwarded_for_symmetric_encoder() {
208 for input in [
209 XForwardedFor(vec!["203.0.113.195".parse().unwrap()]),
210 XForwardedFor(vec![
211 "2001:db8:85a3:8d3:1319:8a2e:370:7348".parse().unwrap(),
212 "203.0.113.195".parse().unwrap(),
213 ]),
214 ] {
215 let mut values = Vec::new();
216 input.encode(&mut values);
217 assert_eq!(XForwardedFor::decode(&mut values.iter()).ok(), Some(input),);
218 }
219 }
220}