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.iter().filter(|p| p.name.eq_ignore_ascii_case(name));
256 let found = if self.policy == DuplicatePolicy::Last {
257 matches.last()
258 } else {
259 matches.next()
260 };
261 found.map(|p| p.value)
262 }
263
264 pub(crate) fn split_at_name(&self, name: &[u8]) -> (Params<'a>, Option<Param<'a>>) {
269 for (index, p) in self.iter().enumerate() {
270 if p.name.eq_ignore_ascii_case(name) {
271 let off = (p.name.as_ptr() as usize).saturating_sub(self.text.as_ptr() as usize);
273 let head = self.text.get(..off).unwrap_or(&[]);
274 let semi = head.iter().rposition(|&b| b == b';').unwrap_or(0);
275 let before = Params {
276 text: self.text.get(..semi).unwrap_or(&[]),
277 count: u32::try_from(index).unwrap_or(u32::MAX),
278 policy: self.policy,
279 };
280 return (before, Some(p));
281 }
282 }
283 (*self, None)
284 }
285
286 #[must_use]
297 pub const fn len(&self) -> usize {
298 self.count as usize
299 }
300
301 #[must_use]
313 pub const fn is_empty(&self) -> bool {
314 self.count == 0
315 }
316
317 #[must_use]
330 pub const fn raw(&self) -> &'a [u8] {
331 self.text
332 }
333}
334
335impl fmt::Debug for Params<'_> {
336 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
337 f.write_str("Params(")?;
338 f.debug_list()
339 .entries(
340 self.iter()
341 .map(|p| core::str::from_utf8(p.name).unwrap_or("?")),
342 )
343 .finish()?;
344 f.write_str(")")
345 }
346}
347
348#[derive(Clone, Debug)]
363pub struct ParamIter<'a> {
364 rest: &'a [u8],
365}
366
367impl<'a> Iterator for ParamIter<'a> {
368 type Item = Param<'a>;
369
370 fn next(&mut self) -> Option<Param<'a>> {
371 loop {
372 let s = self.rest;
374 let semi = s.iter().position(|&b| b == b';')?;
375 let after = semi + 1;
376 let start = after + skip_ows(s.get(after..).unwrap_or(&[]));
377 let tail = s.get(start..).unwrap_or(&[]);
378 let name_len = tail.iter().take_while(|&&b| class::is_tchar(b)).count();
379 if name_len == 0 {
380 self.rest = tail;
381 continue;
382 }
383 let name = tail.get(..name_len).unwrap_or(&[]);
384 let value_text = tail.get(name_len + 1..).unwrap_or(&[]);
385 let Ok((value, n)) = parse_word(value_text) else {
386 self.rest = &[];
387 return None;
388 };
389 self.rest = value_text.get(n..).unwrap_or(&[]);
390 return Some(Param { name, value });
391 }
392 }
393}
394
395#[cfg(test)]
396mod tests {
397 use std::{format, vec::Vec};
398
399 use super::*;
400
401 fn p(s: &[u8]) -> Result<(Params<'_>, usize)> {
402 parse(s, &Limits::DEFAULT)
403 }
404
405 fn names<'a>(ps: &Params<'a>) -> Vec<&'a [u8]> {
406 ps.iter().map(|x| x.name).collect()
407 }
408
409 #[test]
410 fn test_params_edge_cases() {
411 assert_eq!(p(b"").unwrap().1, 0);
412 assert!(p(b";").unwrap().0.is_empty());
413 assert_eq!(p(b";").unwrap().1, 1);
414 assert_eq!(p(b";;").unwrap().1, 2);
415 let (ps, used) = p(b"; a=b").unwrap();
416 assert_eq!((used, names(&ps)), (5, [&b"a"[..]].to_vec()));
417 assert_eq!(p(b";a=").unwrap_err().kind(), ErrorKind::MissingValue);
418 assert_eq!(p(b";a").unwrap_err().kind(), ErrorKind::MissingValue);
419 assert_eq!(p(b";a;b=c").unwrap_err().kind(), ErrorKind::MissingValue);
420 assert_eq!(p(b";a =b").unwrap_err().kind(), ErrorKind::InvalidByte);
421 assert_eq!(p(b";a= b").unwrap_err().kind(), ErrorKind::InvalidByte);
422 assert_eq!(p(b";@=b").unwrap_err().kind(), ErrorKind::NotToken);
423 assert_eq!(p(b";a@=b").unwrap_err().kind(), ErrorKind::NotToken);
424 assert_eq!(p(b";a=\"\"").unwrap().0.get("a").map(|w| w.len()), Some(0));
425 assert!(
426 p(b";a=\"x\\\"y\"")
427 .unwrap()
428 .0
429 .get("a")
430 .unwrap()
431 .eq_bytes(b"x\"y")
432 );
433 assert_eq!(
434 p(b";a=\"x").unwrap_err().kind(),
435 ErrorKind::UnterminatedQuote
436 );
437 assert_eq!(p(b";a=b\rc").unwrap().1, 4);
438 assert_eq!(p(b";a=\x01").unwrap_err().kind(), ErrorKind::Control);
439 }
440
441 #[test]
442 fn test_params_stop_at_list_separator_and_trailing_ows() {
443 let (ps, used) = p(b";a=1 , b").unwrap();
444 assert_eq!((used, ps.len()), (4, 1));
445 let (_, used) = p(b";a=1; ,b").unwrap();
446 assert_eq!(used, 5);
447 let (_, used) = p(b" ;a=1 x").unwrap();
448 assert_eq!(used, 5);
449 }
450
451 #[test]
452 fn test_params_duplicate_refused_case_insensitive() {
453 let e = p(b";A=b;a=c").unwrap_err();
454 assert_eq!((e.kind(), e.offset()), (ErrorKind::DuplicateParameter, 5));
455 assert!(p(b";ab=1;ba=2;aa=3;bb=4").is_ok());
456 }
457
458 #[test]
459 fn test_params_first_and_last_policies() {
460 let first = Limits::DEFAULT.duplicate_params(DuplicatePolicy::First);
461 let last = Limits::DEFAULT.duplicate_params(DuplicatePolicy::Last);
462 let (a, _) = parse(b";a=1;A=2", &first).unwrap();
463 let (b, _) = parse(b";a=1;A=2", &last).unwrap();
464 assert!(a.get("a").unwrap().eq_bytes(b"1"));
465 assert!(b.get("a").unwrap().eq_bytes(b"2"));
466 assert_eq!(a.len(), 2);
467 }
468
469 #[test]
470 fn test_params_count_limit() {
471 let mut v = Vec::new();
472 for i in 0..257 {
473 v.extend_from_slice(format!(";p{i}=v").as_bytes());
474 }
475 let cut = v.len() - format!(";p{}=v", 256).len();
476 assert_eq!(p(&v[..cut]).unwrap().0.len(), 256);
477 assert_eq!(p(&v).unwrap_err().kind(), ErrorKind::TooManyMembers);
478 }
479
480 #[test]
481 fn test_params_debug_prints_names_only() {
482 let (ps, _) = p(b";user=alice;token=\"s3cr3t\"").unwrap();
483 let d = format!("{ps:?}");
484 assert_eq!(d, "Params([\"user\", \"token\"])");
485 assert!(!d.contains("s3cr3t") && !d.contains("alice"));
486 }
487
488 #[test]
489 fn test_params_iter_skips_empty_parameters() {
490 let (ps, _) = p(b";; a=1 ;;b=\"x;y\";").unwrap();
491 assert_eq!(names(&ps), [&b"a"[..], b"b"]);
492 assert!(ps.get("b").unwrap().eq_bytes(b"x;y"));
493 assert_eq!(ps.raw(), b";; a=1 ;;b=\"x;y\";");
494 }
495}