1use core::fmt;
16
17use crate::{
18 class,
19 error::{ErrorKind, Result, err},
20 limits::{DuplicatePolicy, Limits},
21 scan::control_kind,
22 text::{Word, is_ows, parse_word, skip_ows},
23};
24
25#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
27pub struct Param<'a> {
28 pub name: &'a [u8],
30 pub value: Word<'a>,
32}
33
34#[inline]
37fn name_bit(name: &[u8]) -> u64 {
38 let first = name.first().map_or(0, u8::to_ascii_lowercase);
39 let last = name.last().map_or(0, u8::to_ascii_lowercase);
40 let h = (name.len() as u64)
41 .wrapping_mul(31)
42 .wrapping_add(u64::from(first))
43 .wrapping_mul(31)
44 .wrapping_add(u64::from(last));
45 1u64 << (h & 63)
46}
47
48pub fn parse<'a>(s: &'a [u8], limits: &Limits) -> Result<(Params<'a>, usize)> {
75 let policy = limits.duplicate_params;
76 let mut count: usize = 0;
77 let mut used = 0usize;
78 let mut seen: u64 = 0;
79 loop {
80 let ows = skip_ows(s.get(used..).unwrap_or(&[]));
81 let semi = used + ows;
82 if s.get(semi) != Some(&b';') {
83 break;
84 }
85 let mut i = semi + 1;
86 i += skip_ows(s.get(i..).unwrap_or(&[]));
87 match s.get(i) {
88 None | Some(b';') => {
89 used = i;
90 continue;
91 }
92 Some(&b) if !class::is_tchar(b) => {
93 if b == b',' {
96 used = semi + 1;
97 break;
98 }
99 return err(
100 if b < 0x20 || b == 0x7f {
101 control_kind(b)
102 } else {
103 ErrorKind::NotToken
104 },
105 i,
106 );
107 }
108 Some(_) => {}
109 }
110 let name_start = i;
111 let name_len = s
112 .get(i..)
113 .unwrap_or(&[])
114 .iter()
115 .take_while(|&&b| class::is_tchar(b))
116 .count();
117 let name = s.get(name_start..name_start + name_len).unwrap_or(&[]);
118 i += name_len;
119 match s.get(i) {
120 Some(b'=') => i += 1,
121 Some(&b) if is_ows(b) => {
122 let after = i + skip_ows(s.get(i..).unwrap_or(&[]));
123 if s.get(after) == Some(&b'=') {
124 return err(ErrorKind::InvalidByte, i);
125 }
126 return err(ErrorKind::MissingValue, i);
127 }
128 Some(b'"') => return err(ErrorKind::MissingValue, i),
129 Some(&b) if b != b';' && b != b',' && class::is_field_text(b) => {
130 return err(ErrorKind::NotToken, i);
131 }
132 Some(&b) if !class::is_field_text(b) => return err(control_kind(b), i),
133 _ => return err(ErrorKind::MissingValue, i),
134 }
135 let value_start = i;
136 match s.get(i) {
137 Some(&b) if is_ows(b) => return err(ErrorKind::InvalidByte, i),
138 None | Some(b';' | b',') => return err(ErrorKind::MissingValue, i),
139 _ => {}
140 }
141 let rest = s.get(i..).unwrap_or(&[]);
142 let (_, n) = parse_word(rest).map_err(|e| match e.kind() {
143 ErrorKind::Empty => crate::error::ParseError::new(
144 control_or_invalid(rest.first().copied().unwrap_or(0)),
145 value_start,
146 ),
147 _ => e.shifted(value_start),
148 })?;
149 i += n;
150 count += 1;
151 if count > usize::from(limits.params) {
152 return err(ErrorKind::TooManyMembers, name_start);
153 }
154 if policy == DuplicatePolicy::Refuse {
155 let bit = name_bit(name);
156 if seen & bit != 0 {
157 let earlier = Params {
158 text: s.get(..used).unwrap_or(&[]),
159 count: 0,
160 policy,
161 };
162 if earlier.iter().any(|p| p.name.eq_ignore_ascii_case(name)) {
163 return err(ErrorKind::DuplicateParameter, name_start);
164 }
165 }
166 seen |= bit;
167 }
168 used = i;
169 }
170 Ok((
171 Params {
172 text: s.get(..used).unwrap_or(&[]),
173 count: u32::try_from(count).unwrap_or(u32::MAX),
174 policy,
175 },
176 used,
177 ))
178}
179
180#[inline]
181const fn control_or_invalid(b: u8) -> ErrorKind {
182 if b < 0x20 || b == 0x7f {
183 control_kind(b)
184 } else {
185 ErrorKind::InvalidByte
186 }
187}
188
189#[derive(Clone, Copy, PartialEq, Eq, Hash)]
193pub struct Params<'a> {
194 text: &'a [u8],
195 count: u32,
196 policy: DuplicatePolicy,
197}
198
199impl<'a> Params<'a> {
200 #[must_use]
203 pub fn iter(&self) -> ParamIter<'a> {
204 ParamIter { rest: self.text }
205 }
206
207 #[must_use]
210 pub fn get(&self, name: &str) -> Option<Word<'a>> {
211 let name = name.as_bytes();
212 let mut matches = self.iter().filter(|p| p.name.eq_ignore_ascii_case(name));
213 let found = if self.policy == DuplicatePolicy::Last {
214 matches.last()
215 } else {
216 matches.next()
217 };
218 found.map(|p| p.value)
219 }
220
221 #[must_use]
223 pub const fn len(&self) -> usize {
224 self.count as usize
225 }
226
227 #[must_use]
229 pub const fn is_empty(&self) -> bool {
230 self.count == 0
231 }
232
233 #[must_use]
236 pub const fn raw(&self) -> &'a [u8] {
237 self.text
238 }
239}
240
241impl fmt::Debug for Params<'_> {
242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243 f.write_str("Params(")?;
244 f.debug_list()
245 .entries(
246 self.iter()
247 .map(|p| core::str::from_utf8(p.name).unwrap_or("?")),
248 )
249 .finish()?;
250 f.write_str(")")
251 }
252}
253
254#[derive(Clone, Debug)]
256pub struct ParamIter<'a> {
257 rest: &'a [u8],
258}
259
260impl<'a> Iterator for ParamIter<'a> {
261 type Item = Param<'a>;
262
263 fn next(&mut self) -> Option<Param<'a>> {
264 loop {
265 let s = self.rest;
267 let semi = s.iter().position(|&b| b == b';')?;
268 let after = semi + 1;
269 let start = after + skip_ows(s.get(after..).unwrap_or(&[]));
270 let tail = s.get(start..).unwrap_or(&[]);
271 let name_len = tail.iter().take_while(|&&b| class::is_tchar(b)).count();
272 if name_len == 0 {
273 self.rest = tail;
274 continue;
275 }
276 let name = tail.get(..name_len).unwrap_or(&[]);
277 let value_text = tail.get(name_len + 1..).unwrap_or(&[]);
278 let Ok((value, n)) = parse_word(value_text) else {
279 self.rest = &[];
280 return None;
281 };
282 self.rest = value_text.get(n..).unwrap_or(&[]);
283 return Some(Param { name, value });
284 }
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use std::{format, vec::Vec};
291
292 use super::*;
293
294 fn p(s: &[u8]) -> Result<(Params<'_>, usize)> {
295 parse(s, &Limits::DEFAULT)
296 }
297
298 fn names<'a>(ps: &Params<'a>) -> Vec<&'a [u8]> {
299 ps.iter().map(|x| x.name).collect()
300 }
301
302 #[test]
303 fn test_params_edge_cases() {
304 assert_eq!(p(b"").unwrap().1, 0);
305 assert!(p(b";").unwrap().0.is_empty());
306 assert_eq!(p(b";").unwrap().1, 1);
307 assert_eq!(p(b";;").unwrap().1, 2);
308 let (ps, used) = p(b"; a=b").unwrap();
309 assert_eq!((used, names(&ps)), (5, [&b"a"[..]].to_vec()));
310 assert_eq!(p(b";a=").unwrap_err().kind(), ErrorKind::MissingValue);
311 assert_eq!(p(b";a").unwrap_err().kind(), ErrorKind::MissingValue);
312 assert_eq!(p(b";a;b=c").unwrap_err().kind(), ErrorKind::MissingValue);
313 assert_eq!(p(b";a =b").unwrap_err().kind(), ErrorKind::InvalidByte);
314 assert_eq!(p(b";a= b").unwrap_err().kind(), ErrorKind::InvalidByte);
315 assert_eq!(p(b";@=b").unwrap_err().kind(), ErrorKind::NotToken);
316 assert_eq!(p(b";a@=b").unwrap_err().kind(), ErrorKind::NotToken);
317 assert_eq!(p(b";a=\"\"").unwrap().0.get("a").map(|w| w.len()), Some(0));
318 assert!(
319 p(b";a=\"x\\\"y\"")
320 .unwrap()
321 .0
322 .get("a")
323 .unwrap()
324 .eq_bytes(b"x\"y")
325 );
326 assert_eq!(
327 p(b";a=\"x").unwrap_err().kind(),
328 ErrorKind::UnterminatedQuote
329 );
330 assert_eq!(p(b";a=b\rc").unwrap().1, 4);
331 assert_eq!(p(b";a=\x01").unwrap_err().kind(), ErrorKind::Control);
332 }
333
334 #[test]
335 fn test_params_stop_at_list_separator_and_trailing_ows() {
336 let (ps, used) = p(b";a=1 , b").unwrap();
337 assert_eq!((used, ps.len()), (4, 1));
338 let (_, used) = p(b";a=1; ,b").unwrap();
339 assert_eq!(used, 5);
340 let (_, used) = p(b" ;a=1 x").unwrap();
341 assert_eq!(used, 5);
342 }
343
344 #[test]
345 fn test_params_duplicate_refused_case_insensitive() {
346 let e = p(b";A=b;a=c").unwrap_err();
347 assert_eq!((e.kind(), e.offset()), (ErrorKind::DuplicateParameter, 5));
348 assert!(p(b";ab=1;ba=2;aa=3;bb=4").is_ok());
349 }
350
351 #[test]
352 fn test_params_first_and_last_policies() {
353 let first = Limits::DEFAULT.duplicate_params(DuplicatePolicy::First);
354 let last = Limits::DEFAULT.duplicate_params(DuplicatePolicy::Last);
355 let (a, _) = parse(b";a=1;A=2", &first).unwrap();
356 let (b, _) = parse(b";a=1;A=2", &last).unwrap();
357 assert!(a.get("a").unwrap().eq_bytes(b"1"));
358 assert!(b.get("a").unwrap().eq_bytes(b"2"));
359 assert_eq!(a.len(), 2);
360 }
361
362 #[test]
363 fn test_params_count_limit() {
364 let mut v = Vec::new();
365 for i in 0..257 {
366 v.extend_from_slice(format!(";p{i}=v").as_bytes());
367 }
368 let cut = v.len() - format!(";p{}=v", 256).len();
369 assert_eq!(p(&v[..cut]).unwrap().0.len(), 256);
370 assert_eq!(p(&v).unwrap_err().kind(), ErrorKind::TooManyMembers);
371 }
372
373 #[test]
374 fn test_params_debug_prints_names_only() {
375 let (ps, _) = p(b";user=alice;token=\"s3cr3t\"").unwrap();
376 let d = format!("{ps:?}");
377 assert_eq!(d, "Params([\"user\", \"token\"])");
378 assert!(!d.contains("s3cr3t") && !d.contains("alice"));
379 }
380
381 #[test]
382 fn test_params_iter_skips_empty_parameters() {
383 let (ps, _) = p(b";; a=1 ;;b=\"x;y\";").unwrap();
384 assert_eq!(names(&ps), [&b"a"[..], b"b"]);
385 assert!(ps.get("b").unwrap().eq_bytes(b"x;y"));
386 assert_eq!(ps.raw(), b";; a=1 ;;b=\"x;y\";");
387 }
388}