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)]
37pub struct Param<'a> {
38 pub name: &'a [u8],
40 pub value: Word<'a>,
42}
43
44#[inline]
47fn name_bit(name: &[u8]) -> u64 {
48 let first = name.first().map_or(0, u8::to_ascii_lowercase);
49 let last = name.last().map_or(0, u8::to_ascii_lowercase);
50 let h = (name.len() as u64)
51 .wrapping_mul(31)
52 .wrapping_add(u64::from(first))
53 .wrapping_mul(31)
54 .wrapping_add(u64::from(last));
55 1u64 << (h & 63)
56}
57
58pub fn parse<'a>(s: &'a [u8], limits: &Limits) -> Result<(Params<'a>, usize)> {
85 let policy = limits.duplicate_params;
86 let mut count: usize = 0;
87 let mut used = 0usize;
88 let mut seen: u64 = 0;
89 loop {
90 let ows = skip_ows(s.get(used..).unwrap_or(&[]));
91 let semi = used + ows;
92 if s.get(semi) != Some(&b';') {
93 break;
94 }
95 let mut i = semi + 1;
96 i += skip_ows(s.get(i..).unwrap_or(&[]));
97 match s.get(i) {
98 None | Some(b';') => {
99 used = i;
100 continue;
101 }
102 Some(&b) if !class::is_tchar(b) => {
103 if b == b',' {
106 used = semi + 1;
107 break;
108 }
109 return err(
110 if crate::scan::is_control(b) {
111 control_kind(b)
112 } else {
113 ErrorKind::NotToken
114 },
115 i,
116 );
117 }
118 Some(_) => {}
119 }
120 let name_start = i;
121 let name_len = s
122 .get(i..)
123 .unwrap_or(&[])
124 .iter()
125 .take_while(|&&b| class::is_tchar(b))
126 .count();
127 let name = s.get(name_start..name_start + name_len).unwrap_or(&[]);
128 i += name_len;
129 match s.get(i) {
130 Some(b'=') => i += 1,
131 Some(&b) if is_ows(b) => {
132 let after = i + skip_ows(s.get(i..).unwrap_or(&[]));
133 if s.get(after) == Some(&b'=') {
134 return err(ErrorKind::InvalidByte, i);
135 }
136 return err(ErrorKind::MissingValue, i);
137 }
138 Some(b'"') => return err(ErrorKind::MissingValue, i),
139 Some(&b) if b != b';' && b != b',' && class::is_field_text(b) => {
140 return err(ErrorKind::NotToken, i);
141 }
142 Some(&b) if !class::is_field_text(b) => return err(control_kind(b), i),
143 _ => return err(ErrorKind::MissingValue, i),
144 }
145 let value_start = i;
146 match s.get(i) {
147 Some(&b) if is_ows(b) => return err(ErrorKind::InvalidByte, i),
148 None | Some(b';' | b',') => return err(ErrorKind::MissingValue, i),
149 _ => {}
150 }
151 let rest = s.get(i..).unwrap_or(&[]);
152 let (_, n) = parse_word(rest).map_err(|e| match e.kind() {
153 ErrorKind::Empty => crate::error::ParseError::new(
154 control_or_invalid(rest.first().copied().unwrap_or(0)),
155 value_start,
156 ),
157 _ => e.shifted(value_start),
158 })?;
159 i += n;
160 count += 1;
161 if count > usize::from(limits.params) {
162 return err(ErrorKind::TooManyMembers, name_start);
163 }
164 if policy == DuplicatePolicy::Refuse {
165 let bit = name_bit(name);
166 if seen & bit != 0 {
167 let earlier = Params {
168 text: s.get(..used).unwrap_or(&[]),
169 count: 0,
170 policy,
171 };
172 if earlier.iter().any(|p| p.name.eq_ignore_ascii_case(name)) {
173 return err(ErrorKind::DuplicateParameter, name_start);
174 }
175 }
176 seen |= bit;
177 }
178 used = i;
179 }
180 Ok((
181 Params {
182 text: s.get(..used).unwrap_or(&[]),
183 count: u32::try_from(count).unwrap_or(u32::MAX),
184 policy,
185 },
186 used,
187 ))
188}
189
190#[inline]
191const fn control_or_invalid(b: u8) -> ErrorKind {
192 if crate::scan::is_control(b) {
193 control_kind(b)
194 } else {
195 ErrorKind::InvalidByte
196 }
197}
198
199#[derive(Clone, Copy, PartialEq, Eq, Hash)]
214pub struct Params<'a> {
215 pub(crate) text: &'a [u8],
216 pub(crate) count: u32,
217 pub(crate) policy: DuplicatePolicy,
218}
219
220impl<'a> Params<'a> {
221 #[must_use]
235 pub fn iter(&self) -> ParamIter<'a> {
236 ParamIter { rest: self.text }
237 }
238
239 #[must_use]
253 pub fn get(&self, name: &str) -> Option<Word<'a>> {
254 let name = name.as_bytes();
255 let mut matches = self
257 .iter()
258 .filter(|p| p.name == name || p.name.eq_ignore_ascii_case(name));
259 let found = if self.policy == DuplicatePolicy::Last {
260 matches.last()
261 } else {
262 matches.next()
263 };
264 found.map(|p| p.value)
265 }
266
267 pub(crate) fn split_at_name(&self, name: &[u8]) -> (Params<'a>, Option<Param<'a>>) {
272 for (index, p) in self.iter().enumerate() {
273 if p.name.eq_ignore_ascii_case(name) {
274 let off = (p.name.as_ptr() as usize).saturating_sub(self.text.as_ptr() as usize);
276 let head = self.text.get(..off).unwrap_or(&[]);
277 let semi = head.iter().rposition(|&b| b == b';').unwrap_or(0);
278 let before = Params {
279 text: self.text.get(..semi).unwrap_or(&[]),
280 count: u32::try_from(index).unwrap_or(u32::MAX),
281 policy: self.policy,
282 };
283 return (before, Some(p));
284 }
285 }
286 (*self, None)
287 }
288
289 #[must_use]
300 pub const fn len(&self) -> usize {
301 self.count as usize
302 }
303
304 #[must_use]
316 pub const fn is_empty(&self) -> bool {
317 self.count == 0
318 }
319
320 #[must_use]
333 pub const fn raw(&self) -> &'a [u8] {
334 self.text
335 }
336}
337
338impl fmt::Debug for Params<'_> {
339 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340 f.write_str("Params(")?;
341 f.debug_list()
342 .entries(
343 self.iter()
344 .map(|p| core::str::from_utf8(p.name).unwrap_or("?")),
345 )
346 .finish()?;
347 f.write_str(")")
348 }
349}
350
351#[derive(Clone, Debug)]
366pub struct ParamIter<'a> {
367 rest: &'a [u8],
368}
369
370impl<'a> Iterator for ParamIter<'a> {
371 type Item = Param<'a>;
372
373 fn next(&mut self) -> Option<Param<'a>> {
374 loop {
375 let s = self.rest;
377 let semi = s.iter().position(|&b| b == b';')?;
378 let after = semi + 1;
379 let start = after + skip_ows(s.get(after..).unwrap_or(&[]));
380 let tail = s.get(start..).unwrap_or(&[]);
381 let name_len = tail.iter().take_while(|&&b| class::is_tchar(b)).count();
382 if name_len == 0 {
383 self.rest = tail;
384 continue;
385 }
386 let name = tail.get(..name_len).unwrap_or(&[]);
387 let value_text = tail.get(name_len + 1..).unwrap_or(&[]);
388 let Ok((value, n)) = parse_word(value_text) else {
389 self.rest = &[];
390 return None;
391 };
392 self.rest = value_text.get(n..).unwrap_or(&[]);
393 return Some(Param { name, value });
394 }
395 }
396}
397
398#[cfg(test)]
399mod tests {
400 use std::{format, vec::Vec};
401
402 use super::*;
403
404 fn p(s: &[u8]) -> Result<(Params<'_>, usize)> {
405 parse(s, &Limits::DEFAULT)
406 }
407
408 fn names<'a>(ps: &Params<'a>) -> Vec<&'a [u8]> {
409 ps.iter().map(|x| x.name).collect()
410 }
411
412 #[test]
413 fn test_params_edge_cases() {
414 assert_eq!(p(b"").unwrap().1, 0);
415 assert!(p(b";").unwrap().0.is_empty());
416 assert_eq!(p(b";").unwrap().1, 1);
417 assert_eq!(p(b";;").unwrap().1, 2);
418 let (ps, used) = p(b"; a=b").unwrap();
419 assert_eq!((used, names(&ps)), (5, [&b"a"[..]].to_vec()));
420 assert_eq!(p(b";a=").unwrap_err().kind(), ErrorKind::MissingValue);
421 assert_eq!(p(b";a").unwrap_err().kind(), ErrorKind::MissingValue);
422 assert_eq!(p(b";a;b=c").unwrap_err().kind(), ErrorKind::MissingValue);
423 assert_eq!(p(b";a =b").unwrap_err().kind(), ErrorKind::InvalidByte);
424 assert_eq!(p(b";a= b").unwrap_err().kind(), ErrorKind::InvalidByte);
425 assert_eq!(p(b";@=b").unwrap_err().kind(), ErrorKind::NotToken);
426 assert_eq!(p(b";a@=b").unwrap_err().kind(), ErrorKind::NotToken);
427 assert_eq!(p(b";a=\"\"").unwrap().0.get("a").map(|w| w.len()), Some(0));
428 assert!(
429 p(b";a=\"x\\\"y\"")
430 .unwrap()
431 .0
432 .get("a")
433 .unwrap()
434 .eq_bytes(b"x\"y")
435 );
436 assert_eq!(
437 p(b";a=\"x").unwrap_err().kind(),
438 ErrorKind::UnterminatedQuote
439 );
440 assert_eq!(p(b";a=b\rc").unwrap().1, 4);
441 assert_eq!(p(b";a=\x01").unwrap_err().kind(), ErrorKind::Control);
442 }
443
444 #[test]
445 fn test_params_stop_at_list_separator_and_trailing_ows() {
446 let (ps, used) = p(b";a=1 , b").unwrap();
447 assert_eq!((used, ps.len()), (4, 1));
448 let (_, used) = p(b";a=1; ,b").unwrap();
449 assert_eq!(used, 5);
450 let (_, used) = p(b" ;a=1 x").unwrap();
451 assert_eq!(used, 5);
452 }
453
454 #[test]
455 fn test_params_duplicate_refused_case_insensitive() {
456 let e = p(b";A=b;a=c").unwrap_err();
457 assert_eq!((e.kind(), e.offset()), (ErrorKind::DuplicateParameter, 5));
458 assert!(p(b";ab=1;ba=2;aa=3;bb=4").is_ok());
459 }
460
461 #[test]
462 fn test_params_first_and_last_policies() {
463 let first = Limits::DEFAULT.duplicate_params(DuplicatePolicy::First);
464 let last = Limits::DEFAULT.duplicate_params(DuplicatePolicy::Last);
465 let (a, _) = parse(b";a=1;A=2", &first).unwrap();
466 let (b, _) = parse(b";a=1;A=2", &last).unwrap();
467 assert!(a.get("a").unwrap().eq_bytes(b"1"));
468 assert!(b.get("a").unwrap().eq_bytes(b"2"));
469 assert_eq!(a.len(), 2);
470 }
471
472 #[test]
473 fn test_params_count_limit() {
474 let mut v = Vec::new();
475 for i in 0..257 {
476 v.extend_from_slice(format!(";p{i}=v").as_bytes());
477 }
478 let cut = v.len() - format!(";p{}=v", 256).len();
479 assert_eq!(p(&v[..cut]).unwrap().0.len(), 256);
480 assert_eq!(p(&v).unwrap_err().kind(), ErrorKind::TooManyMembers);
481 }
482
483 #[test]
484 fn test_params_debug_prints_names_only() {
485 let (ps, _) = p(b";user=alice;token=\"s3cr3t\"").unwrap();
486 let d = format!("{ps:?}");
487 assert_eq!(d, "Params([\"user\", \"token\"])");
488 assert!(!d.contains("s3cr3t") && !d.contains("alice"));
489 }
490
491 #[test]
492 fn test_params_iter_skips_empty_parameters() {
493 let (ps, _) = p(b";; a=1 ;;b=\"x;y\";").unwrap();
494 assert_eq!(names(&ps), [&b"a"[..], b"b"]);
495 assert!(ps.get("b").unwrap().eq_bytes(b"x;y"));
496 assert_eq!(ps.raw(), b";; a=1 ;;b=\"x;y\";");
497 }
498}