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