1use core::{marker, fmt};
4use core::net::IpAddr;
5
6const FORWARDED_SEP: char = ',';
10const ENTRY_SEP: char = ';';
11const PAIR_SEP: char = '=';
12
13#[derive(Clone, Copy, PartialEq, Eq, Debug)]
14pub enum ForwardedNode<'a> {
18 Ip(IpAddr),
20 Name(&'a str),
22 Unknown,
24}
25
26impl<'a> ForwardedNode<'a> {
27 #[inline(always)]
28 fn parse_name(name: &'a str) -> Self {
29 if let Ok(name) = name.parse() {
30 return Self::Ip(name);
31 } else {
32 return Self::Name(name)
33 }
34 }
35
36 pub fn parse_node(mut node: &'a str) -> Self {
38 node = node.trim_matches('"');
39 if node.eq_ignore_ascii_case("unknown") {
40 return Self::Unknown;
41 }
42
43 if let Some(mut ipv6) = node.strip_prefix('[') {
44 if let Some(end_addr_idx) = ipv6.find(']') {
45 ipv6 = &ipv6[..end_addr_idx];
46 return Self::parse_name(ipv6);
47 } else {
48 return Self::Name(ipv6);
49 }
50 }
51
52 let mut node = node.rsplit(':');
53 let port_or_ip = node.next().unwrap();
54 let ip = if let Some(ip) = node.next() {
55 ip
56 } else {
57 port_or_ip
58 };
59
60 ForwardedNode::parse_name(ip)
61 }
62}
63
64impl fmt::Display for ForwardedNode<'_> {
65 #[inline(always)]
66 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
67 match self {
68 Self::Ip(ip) => fmt::Display::fmt(&ip, fmt),
69 Self::Name(ip) => fmt.write_str(&ip),
70 Self::Unknown => fmt.write_str("-"),
71 }
72 }
73}
74
75#[derive(Copy, Clone, PartialEq, Eq, Debug)]
76pub enum ForwardedValue<'a> {
78 By(ForwardedNode<'a>),
82 For(ForwardedNode<'a>),
86 Host(&'a str),
88 Protocol(&'a str)
92}
93
94pub struct ForwardedEntryIter<'a> {
96 components: core::str::Split<'a, char>,
97}
98
99impl<'a> ForwardedEntryIter<'a> {
100 pub fn parse_entry(value: &'a str) -> Self {
108 Self {
109 components: value.split(ENTRY_SEP)
110 }
111 }
112}
113
114impl<'a> Iterator for ForwardedEntryIter<'a> {
115 type Item = ForwardedValue<'a>;
116
117 fn next(&mut self) -> Option<Self::Item> {
118 while let Some(value) = self.components.next() {
119 let mut pairs = value.splitn(2, PAIR_SEP);
120 let key = pairs.next().unwrap();
121 if key.eq_ignore_ascii_case("for") {
122 if let Some(node) = pairs.next() {
123 return Some(ForwardedValue::For(ForwardedNode::parse_node(node)))
124 }
125 } else if key.eq_ignore_ascii_case("by") {
126 if let Some(node) = pairs.next() {
127 return Some(ForwardedValue::By(ForwardedNode::parse_node(node)))
128 }
129 } else if key.eq_ignore_ascii_case("proto") {
130 if let Some(proto) = pairs.next() {
131 return Some(ForwardedValue::Protocol(proto))
132 }
133 } else if key.eq_ignore_ascii_case("host") {
134 if let Some(host) = pairs.next() {
135 return Some(ForwardedValue::Host(host))
136 }
137 }
138 }
139
140 None
141 }
142}
143
144pub struct ForwardedIter<'a, I> {
146 components: I,
147 _lifetime: marker::PhantomData<&'a I>,
148}
149
150impl<'a, I: Iterator<Item = &'a str> + 'a> Iterator for ForwardedIter<'a, I> {
151 type Item = ForwardedEntryIter<'a>;
152
153 #[inline]
154 fn next(&mut self) -> Option<Self::Item> {
155 self.components.next().map(ForwardedEntryIter::parse_entry)
156 }
157}
158
159pub struct ForwardedForIter<'a, I> {
165 components: I,
166 _lifetime: marker::PhantomData<&'a I>,
167}
168
169impl<'a, I: Iterator<Item = &'a str> + 'a> Iterator for ForwardedForIter<'a, I> {
170 type Item = ForwardedNode<'a>;
171
172 #[inline]
173 fn next(&mut self) -> Option<Self::Item> {
174 while let Some(value) = self.components.next() {
175 let mut pairs = value.splitn(2, PAIR_SEP);
176 let key = pairs.next().unwrap();
177 if key.eq_ignore_ascii_case("for") {
178 if let Some(node) = pairs.next() {
179 return Some(ForwardedNode::parse_node(node))
180 }
181 }
182 }
183
184 None
185 }
186}
187
188#[inline(always)]
189pub fn parse_forwarded<'a>(value: &'a str) -> ForwardedIter<'a, impl Iterator<Item = &'a str>> {
197 ForwardedIter {
198 components: value.split(FORWARDED_SEP),
199 _lifetime: marker::PhantomData,
200 }
201}
202
203#[inline(always)]
204pub fn parse_forwarded_rev<'a>(value: &'a str) -> ForwardedIter<'a, impl Iterator<Item = &'a str>> {
206 ForwardedIter {
207 components: value.rsplit(FORWARDED_SEP),
208 _lifetime: marker::PhantomData,
209 }
210}
211
212#[inline(always)]
213pub fn parse_forwarded_for<'a>(value: &'a str) -> ForwardedForIter<'a, impl Iterator<Item = &'a str>> {
215 ForwardedForIter {
216 components: value.split([FORWARDED_SEP, ENTRY_SEP]),
217 _lifetime: marker::PhantomData,
218 }
219}
220
221#[inline(always)]
222pub fn parse_forwarded_for_rev<'a>(value: &'a str) -> ForwardedForIter<'a, impl Iterator<Item = &'a str>> {
224 ForwardedForIter {
225 components: value.rsplit([FORWARDED_SEP, ENTRY_SEP]),
226 _lifetime: marker::PhantomData,
227 }
228}