1use core::fmt;
17
18use crate::{
19 class,
20 error::{ErrorKind, Result, err},
21 limits::{DuplicatePolicy, Limits},
22 scan::control_kind,
23 text::{Word, is_ows, parse_quoted, token_len, validated_word},
24};
25
26#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
38pub struct Param<'a> {
39 pub name: &'a [u8],
41 pub value: Word<'a>,
43}
44
45pub const MAX_CHECKED_PARAMS: usize = 64;
68
69const INLINE_NAMES: usize = 8;
72
73pub(crate) struct Names {
78 first: [usize; INLINE_NAMES],
79 rest: Option<[usize; MAX_CHECKED_PARAMS - INLINE_NAMES]>,
80 len: usize,
81 seen: u64,
82}
83
84impl Names {
85 #[inline]
86 pub(crate) const fn new() -> Self {
87 Self {
88 first: [0; INLINE_NAMES],
89 rest: None,
90 len: 0,
91 seen: 0,
92 }
93 }
94
95 #[inline]
99 pub(crate) fn repeats(
100 &mut self,
101 text: &[u8],
102 off: usize,
103 name: &[u8],
104 in_name: fn(u8) -> bool,
105 ) -> bool {
106 let bit = name_bit(name);
107 if self.seen & bit == 0 {
108 if let Some(slot) = self.first.get_mut(self.len) {
109 self.seen |= bit;
110 *slot = off;
111 self.len += 1;
112 return false;
113 }
114 }
115 self.repeats_slow(text, off, name, in_name, bit)
116 }
117
118 #[cold]
121 fn repeats_slow(
122 &mut self,
123 text: &[u8],
124 off: usize,
125 name: &[u8],
126 in_name: fn(u8) -> bool,
127 bit: u64,
128 ) -> bool {
129 if self.seen & bit != 0 {
130 let l = name.len();
131 let same = |&o: &usize| {
132 text.get(o + l).is_none_or(|&b| !in_name(b))
133 && text
134 .get(o..o + l)
135 .is_some_and(|e| e.eq_ignore_ascii_case(name))
136 };
137 let inline = self.first.get(..self.len.min(INLINE_NAMES));
138 let spilled = self.len.saturating_sub(INLINE_NAMES);
139 let rest = self.rest.as_ref().and_then(|r| r.get(..spilled));
140 if inline.unwrap_or(&[]).iter().any(same) || rest.unwrap_or(&[]).iter().any(same) {
141 return true;
142 }
143 }
144 self.seen |= bit;
145 let slot = match self.len.checked_sub(INLINE_NAMES) {
146 None => self.first.get_mut(self.len),
147 Some(i) => self
148 .rest
149 .get_or_insert([0; MAX_CHECKED_PARAMS - INLINE_NAMES])
150 .get_mut(i),
151 };
152 if let Some(slot) = slot {
153 *slot = off;
154 self.len += 1;
155 }
156 false
157 }
158}
159
160#[inline]
163fn name_bit(name: &[u8]) -> u64 {
164 let first = name.first().map_or(0, u8::to_ascii_lowercase);
165 let last = name.last().map_or(0, u8::to_ascii_lowercase);
166 let h = (name.len() as u64)
167 .wrapping_mul(31)
168 .wrapping_add(u64::from(first))
169 .wrapping_mul(31)
170 .wrapping_add(u64::from(last));
171 1u64 << (h & 63)
172}
173
174pub fn parse<'a>(s: &'a [u8], limits: &Limits) -> Result<(Params<'a>, usize)> {
201 walk::<false>(s, limits)
202}
203
204pub fn parse_optional<'a>(s: &'a [u8], limits: &Limits) -> Result<(OptionalParams<'a>, usize)> {
241 let (p, used) = walk::<true>(s, limits)?;
242 Ok((
243 OptionalParams {
244 text: p.text,
245 count: p.count,
246 policy: p.policy,
247 },
248 used,
249 ))
250}
251
252#[inline]
257fn walk<'a, const OPTIONAL: bool>(s: &'a [u8], limits: &Limits) -> Result<(Params<'a>, usize)> {
258 let policy = limits.duplicate_params;
259 let refuse = policy == DuplicatePolicy::Refuse;
260 let max = if refuse {
261 usize::from(limits.params).min(MAX_CHECKED_PARAMS)
262 } else {
263 usize::from(limits.params)
264 };
265 let at = |rest: &[u8]| s.len() - rest.len();
268 let (mut done, mut count) = (s, 0usize);
269 let mut names = Names::new();
270 while let [b';', after @ ..] = skip_ws(done) {
271 let r = skip_ws(after);
272 let n = token_len(r);
273 if n == 0 {
274 match r.first() {
275 None | Some(b';') => {
276 done = r;
277 continue;
278 }
279 Some(b',') => {
282 done = after;
283 break;
284 }
285 Some(&b) => {
286 let kind = if crate::scan::is_control(b) {
287 control_kind(b)
288 } else {
289 ErrorKind::NotToken
290 };
291 return err(kind, at(r));
292 }
293 }
294 }
295 let name_at = at(r);
296 let (name, r) = r.split_at(n);
297 let bare = OPTIONAL
300 && match r {
301 [] | [b';' | b',', ..] => true,
302 [b, ..] if is_ows(*b) => skip_ws(r).first() != Some(&b'='),
303 _ => false,
304 };
305 let next = if bare {
307 r
308 } else {
309 let value = match r {
310 [b'=', value @ ..] => value,
311 [b, ..] if is_ows(*b) => {
312 let kind = if skip_ws(r).first() == Some(&b'=') {
313 ErrorKind::InvalidByte
314 } else {
315 ErrorKind::MissingValue
316 };
317 return err(kind, at(r));
318 }
319 [b'"', ..] => return err(ErrorKind::MissingValue, at(r)),
320 [b, ..] if *b != b';' && *b != b',' && class::is_field_text(*b) => {
321 return err(ErrorKind::NotToken, at(r));
322 }
323 [b, ..] if !class::is_field_text(*b) => return err(control_kind(*b), at(r)),
324 _ => return err(ErrorKind::MissingValue, at(r)),
325 };
326 let used = match value {
327 [b, ..] if is_ows(*b) => return err(ErrorKind::InvalidByte, at(value)),
328 [] | [b';' | b',', ..] => return err(ErrorKind::MissingValue, at(value)),
329 [b'"', ..] => parse_quoted(value).map_err(|e| e.shifted(at(value)))?.1,
330 [b, ..] => match token_len(value) {
331 0 => return err(control_or_invalid(*b), at(value)),
332 n => n,
333 },
334 };
335 value.get(used..).unwrap_or(&[])
336 };
337 count += 1;
338 if count > max {
339 return err(ErrorKind::TooManyMembers, name_at);
340 }
341 if refuse && names.repeats(s, name_at, name, class::is_tchar) {
342 return err(ErrorKind::DuplicateParameter, name_at);
343 }
344 done = next;
345 }
346 let used = at(done);
347 Ok((
348 Params {
349 text: s.get(..used).unwrap_or(&[]),
350 count: u32::try_from(count).unwrap_or(u32::MAX),
351 policy,
352 },
353 used,
354 ))
355}
356
357#[inline]
359fn skip_ws(s: &[u8]) -> &[u8] {
360 match s {
361 [b' ' | b'\t', ..] => {
362 let n = s
363 .iter()
364 .position(|&b| b != b' ' && b != b'\t')
365 .unwrap_or(s.len());
366 s.get(n..).unwrap_or(&[])
367 }
368 _ => s,
369 }
370}
371
372#[inline]
373const fn control_or_invalid(b: u8) -> ErrorKind {
374 if crate::scan::is_control(b) {
375 control_kind(b)
376 } else {
377 ErrorKind::InvalidByte
378 }
379}
380
381#[derive(Clone, Copy, PartialEq, Eq, Hash)]
396pub struct Params<'a> {
397 pub(crate) text: &'a [u8],
398 pub(crate) count: u32,
399 pub(crate) policy: DuplicatePolicy,
400}
401
402impl<'a> Params<'a> {
403 #[must_use]
417 pub fn iter(&self) -> ParamIter<'a> {
418 ParamIter { rest: self.text }
419 }
420
421 #[must_use]
435 pub fn get(&self, name: &str) -> Option<Word<'a>> {
436 let name = name.as_bytes();
437 let last = self.policy == DuplicatePolicy::Last;
438 let mut found = None;
439 let mut rest = self.text;
445 while let [b';', after @ ..] = skip_ws(rest) {
446 let tail = skip_ws(after);
447 let value = match tail.split_at_checked(name.len()) {
448 Some((head, [b'=', value @ ..]))
451 if (head == name || head.eq_ignore_ascii_case(name))
452 && head.first().is_some_and(|&b| class::is_tchar(b))
453 && !name.contains(&b'=') =>
454 {
455 let (word, used) = validated_word(value);
456 if !last {
457 return Some(word);
458 }
459 found = Some(word);
460 rest = value.get(used..).unwrap_or(&[]);
461 continue;
462 }
463 _ => match token_len(tail) {
464 0 => {
465 rest = tail;
466 continue;
467 }
468 n => tail.get(n + 1..).unwrap_or(&[]),
469 },
470 };
471 rest = value.get(validated_word(value).1..).unwrap_or(&[]);
472 }
473 found
474 }
475
476 pub(crate) fn split_at_name(&self, name: &[u8]) -> (Params<'a>, Option<Param<'a>>) {
481 for (index, p) in self.iter().enumerate() {
482 if p.name.eq_ignore_ascii_case(name) {
483 let off = (p.name.as_ptr() as usize).saturating_sub(self.text.as_ptr() as usize);
485 let head = self.text.get(..off).unwrap_or(&[]);
486 let semi = head.iter().rposition(|&b| b == b';').unwrap_or(0);
487 let mut text = self.text.get(..semi).unwrap_or(&[]);
488 while let [rest @ .., b' ' | b'\t'] = text {
489 text = rest;
490 }
491 let before = Params {
492 text,
493 count: u32::try_from(index).unwrap_or(u32::MAX),
494 policy: self.policy,
495 };
496 return (before, Some(p));
497 }
498 }
499 (*self, None)
500 }
501
502 #[must_use]
513 pub const fn len(&self) -> usize {
514 self.count as usize
515 }
516
517 #[must_use]
529 pub const fn is_empty(&self) -> bool {
530 self.count == 0
531 }
532
533 #[must_use]
546 pub const fn raw(&self) -> &'a [u8] {
547 self.text
548 }
549}
550
551impl fmt::Debug for Params<'_> {
552 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553 f.write_str("Params(")?;
554 f.debug_list()
555 .entries(
556 self.iter()
557 .map(|p| core::str::from_utf8(p.name).unwrap_or("?")),
558 )
559 .finish()?;
560 f.write_str(")")
561 }
562}
563
564#[derive(Clone, Debug)]
579pub struct ParamIter<'a> {
580 rest: &'a [u8],
581}
582
583impl<'a> Iterator for ParamIter<'a> {
584 type Item = Param<'a>;
585
586 fn next(&mut self) -> Option<Param<'a>> {
587 loop {
588 let [b';', after @ ..] = skip_ws(self.rest) else {
590 self.rest = &[];
591 return None;
592 };
593 let tail = skip_ws(after);
594 let n = token_len(tail);
595 let Some((name, [_, value_text @ ..])) = (n > 0).then(|| tail.split_at(n)) else {
596 self.rest = tail;
597 continue;
598 };
599 let (value, used) = validated_word(value_text);
600 self.rest = value_text.get(used..).unwrap_or(&[]);
601 return Some(Param { name, value });
602 }
603 }
604}
605
606#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
623pub struct OptionalParam<'a> {
624 pub name: &'a [u8],
626 pub value: Option<Word<'a>>,
628}
629
630#[derive(Clone, Copy, PartialEq, Eq, Hash)]
646pub struct OptionalParams<'a> {
647 text: &'a [u8],
648 count: u32,
649 policy: DuplicatePolicy,
650}
651
652impl<'a> OptionalParams<'a> {
653 #[must_use]
667 pub fn iter(&self) -> OptionalParamIter<'a> {
668 OptionalParamIter { rest: self.text }
669 }
670
671 #[must_use]
687 pub fn find(&self, name: &str) -> Option<OptionalParam<'a>> {
688 let name = name.as_bytes();
689 let mut matching = self.iter().filter(|p| p.name.eq_ignore_ascii_case(name));
690 if self.policy == DuplicatePolicy::Last {
691 matching.last()
692 } else {
693 matching.next()
694 }
695 }
696
697 #[must_use]
711 pub fn contains(&self, name: &str) -> bool {
712 let name = name.as_bytes();
713 self.iter().any(|p| p.name.eq_ignore_ascii_case(name))
714 }
715
716 #[must_use]
727 pub const fn len(&self) -> usize {
728 self.count as usize
729 }
730
731 #[must_use]
743 pub const fn is_empty(&self) -> bool {
744 self.count == 0
745 }
746
747 #[must_use]
760 pub const fn raw(&self) -> &'a [u8] {
761 self.text
762 }
763}
764
765impl fmt::Debug for OptionalParams<'_> {
766 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
767 f.write_str("OptionalParams(")?;
768 f.debug_list()
769 .entries(
770 self.iter()
771 .map(|p| core::str::from_utf8(p.name).unwrap_or("?")),
772 )
773 .finish()?;
774 f.write_str(")")
775 }
776}
777
778#[derive(Clone, Debug)]
793pub struct OptionalParamIter<'a> {
794 rest: &'a [u8],
795}
796
797impl<'a> Iterator for OptionalParamIter<'a> {
798 type Item = OptionalParam<'a>;
799
800 fn next(&mut self) -> Option<OptionalParam<'a>> {
801 loop {
802 let [b';', after @ ..] = skip_ws(self.rest) else {
804 self.rest = &[];
805 return None;
806 };
807 let tail = skip_ws(after);
808 let n = token_len(tail);
809 if n == 0 {
810 self.rest = tail;
811 continue;
812 }
813 let (name, r) = tail.split_at(n);
814 let [b'=', value_text @ ..] = r else {
815 self.rest = r;
816 return Some(OptionalParam { name, value: None });
817 };
818 let (value, used) = validated_word(value_text);
819 self.rest = value_text.get(used..).unwrap_or(&[]);
820 return Some(OptionalParam {
821 name,
822 value: Some(value),
823 });
824 }
825 }
826}
827
828#[cfg(test)]
829mod tests {
830 use std::{format, string::String, vec, vec::Vec};
831
832 use proptest::prelude::{Just, Strategy, prop, prop_assert_eq, prop_oneof};
833
834 use super::*;
835
836 fn p(s: &[u8]) -> Result<(Params<'_>, usize)> {
837 parse(s, &Limits::DEFAULT)
838 }
839
840 fn names<'a>(ps: &Params<'a>) -> Vec<&'a [u8]> {
841 ps.iter().map(|x| x.name).collect()
842 }
843
844 #[test]
845 fn test_params_edge_cases() {
846 assert_eq!(p(b"").unwrap().1, 0);
847 assert!(p(b";").unwrap().0.is_empty());
848 assert_eq!(p(b";").unwrap().1, 1);
849 assert_eq!(p(b";;").unwrap().1, 2);
850 let (ps, used) = p(b"; a=b").unwrap();
851 assert_eq!((used, names(&ps)), (5, [&b"a"[..]].to_vec()));
852 assert_eq!(p(b";a=").unwrap_err().kind(), ErrorKind::MissingValue);
853 assert_eq!(p(b";a").unwrap_err().kind(), ErrorKind::MissingValue);
854 assert_eq!(p(b";a;b=c").unwrap_err().kind(), ErrorKind::MissingValue);
855 assert_eq!(p(b";a =b").unwrap_err().kind(), ErrorKind::InvalidByte);
856 assert_eq!(p(b";a= b").unwrap_err().kind(), ErrorKind::InvalidByte);
857 assert_eq!(p(b";@=b").unwrap_err().kind(), ErrorKind::NotToken);
858 assert_eq!(p(b";a@=b").unwrap_err().kind(), ErrorKind::NotToken);
859 assert_eq!(p(b";a=\"\"").unwrap().0.get("a").map(|w| w.len()), Some(0));
860 assert!(
861 p(b";a=\"x\\\"y\"")
862 .unwrap()
863 .0
864 .get("a")
865 .unwrap()
866 .eq_bytes(b"x\"y")
867 );
868 assert_eq!(
869 p(b";a=\"x").unwrap_err().kind(),
870 ErrorKind::UnterminatedQuote
871 );
872 assert_eq!(p(b";a=b\rc").unwrap().1, 4);
873 assert_eq!(p(b";a=\x01").unwrap_err().kind(), ErrorKind::Control);
874 }
875
876 #[test]
877 fn test_params_stop_at_list_separator_and_trailing_ows() {
878 let (ps, used) = p(b";a=1 , b").unwrap();
879 assert_eq!((used, ps.len()), (4, 1));
880 let (_, used) = p(b";a=1; ,b").unwrap();
881 assert_eq!(used, 5);
882 let (_, used) = p(b" ;a=1 x").unwrap();
883 assert_eq!(used, 5);
884 }
885
886 #[test]
887 fn test_params_duplicate_refused_case_insensitive() {
888 let e = p(b";A=b;a=c").unwrap_err();
889 assert_eq!((e.kind(), e.offset()), (ErrorKind::DuplicateParameter, 5));
890 assert!(p(b";ab=1;ba=2;aa=3;bb=4").is_ok());
891 }
892
893 #[test]
894 fn test_params_first_and_last_policies() {
895 let first = Limits::DEFAULT.duplicate_params(DuplicatePolicy::First);
896 let last = Limits::DEFAULT.duplicate_params(DuplicatePolicy::Last);
897 let (a, _) = parse(b";a=1;A=2", &first).unwrap();
898 let (b, _) = parse(b";a=1;A=2", &last).unwrap();
899 assert!(a.get("a").unwrap().eq_bytes(b"1"));
900 assert!(b.get("a").unwrap().eq_bytes(b"2"));
901 assert_eq!(a.len(), 2);
902 }
903
904 #[test]
905 fn test_params_count_limit() {
906 let mut v = Vec::new();
907 for i in 0..257 {
908 v.extend_from_slice(format!(";p{i}=v").as_bytes());
909 }
910 let cut = v.len() - format!(";p{}=v", 256).len();
911 for policy in [DuplicatePolicy::First, DuplicatePolicy::Last] {
913 let l = Limits::DEFAULT.duplicate_params(policy);
914 assert_eq!(parse(&v[..cut], &l).unwrap().0.len(), 256);
915 assert_eq!(parse(&v, &l).unwrap_err().kind(), ErrorKind::TooManyMembers);
916 }
917 let upto = |n: usize| {
919 (0..n)
920 .map(|i| format!(";p{i}=v"))
921 .collect::<Vec<_>>()
922 .concat()
923 };
924 assert_eq!(p(upto(MAX_CHECKED_PARAMS).as_bytes()).unwrap().0.len(), 64);
925 let over = upto(MAX_CHECKED_PARAMS + 1);
926 let e = p(over.as_bytes()).unwrap_err();
927 let last = over.rfind(';').unwrap() + 1;
928 assert_eq!((e.kind(), e.offset()), (ErrorKind::TooManyMembers, last));
929 let wide = Limits::DEFAULT.max_params(u16::MAX);
930 assert_eq!(
931 parse(over.as_bytes(), &wide).unwrap_err().kind(),
932 ErrorKind::TooManyMembers
933 );
934 assert_eq!(
935 parse(upto(3).as_bytes(), &Limits::DEFAULT.max_params(2))
936 .unwrap_err()
937 .kind(),
938 ErrorKind::TooManyMembers
939 );
940 }
941
942 #[test]
943 fn test_params_duplicate_found_in_every_table_slot() {
944 let base = (0..63)
948 .map(|i| format!(";p{i}=\"v;p{i}=w\""))
949 .collect::<Vec<_>>()
950 .concat();
951 for i in 0..63 {
952 let dup = format!("{base};P{i}=x");
953 let e = p(dup.as_bytes()).unwrap_err();
954 assert_eq!(
955 (e.kind(), e.offset()),
956 (ErrorKind::DuplicateParameter, base.len() + 1),
957 "{i}"
958 );
959 }
960 for other in ["p", "p1x", "xp1", "p100"] {
961 assert!(p(format!("{base};{other}=x").as_bytes()).is_ok(), "{other}");
962 }
963 }
964
965 #[test]
966 fn test_params_debug_prints_names_only() {
967 let (ps, _) = p(b";user=alice;token=\"s3cr3t\"").unwrap();
968 let d = format!("{ps:?}");
969 assert_eq!(d, "Params([\"user\", \"token\"])");
970 assert!(!d.contains("s3cr3t") && !d.contains("alice"));
971 }
972
973 #[test]
974 fn test_params_iter_skips_empty_parameters() {
975 let (ps, _) = p(b";; a=1 ;;b=\"x;y\";").unwrap();
976 assert_eq!(names(&ps), [&b"a"[..], b"b"]);
977 assert!(ps.get("b").unwrap().eq_bytes(b"x;y"));
978 assert_eq!(ps.raw(), b";; a=1 ;;b=\"x;y\";");
979 }
980
981 #[test]
982 fn test_params_get_matches_whole_names_only() {
983 let (ps, _) = p(b";;a=\"\"").unwrap();
986 assert!(ps.get(";a").is_none());
987 assert!(ps.get("a").is_some_and(|v| v.eq_bytes(b"")));
988 let (ps, _) = p(b";a=b;c=d").unwrap();
989 for name in ["a=b", "a=b;c", "", ";", "=", "a;", " a"] {
990 assert!(ps.get(name).is_none(), "{name}");
991 }
992 assert!(ps.get("C").is_some_and(|v| v.eq_bytes(b"d")));
993 }
994
995 fn po(s: &[u8]) -> Result<(OptionalParams<'_>, usize)> {
996 parse_optional(s, &Limits::DEFAULT)
997 }
998
999 fn values<'a>(ps: &OptionalParams<'a>) -> Vec<(&'a [u8], Option<&'a [u8]>)> {
1000 ps.iter()
1001 .map(|x| (x.name, x.value.map(|v| v.as_plain().unwrap())))
1002 .collect()
1003 }
1004
1005 #[test]
1006 fn test_optional_params_permessage_deflate_offers() {
1007 let (ps, used) = po(b"; client_max_window_bits").unwrap();
1009 assert_eq!(
1010 (used, values(&ps)),
1011 (24, [(&b"client_max_window_bits"[..], None)].to_vec())
1012 );
1013 let (ps, used) =
1014 po(b"; server_no_context_takeover; client_max_window_bits=15 , permessage-deflate")
1015 .unwrap();
1016 assert_eq!(used, 55);
1017 assert_eq!(
1018 values(&ps),
1019 [
1020 (&b"server_no_context_takeover"[..], None),
1021 (&b"client_max_window_bits"[..], Some(&b"15"[..])),
1022 ]
1023 );
1024 let (ps, _) = po(b";client_max_window_bits=\"10\"").unwrap();
1025 assert!(
1026 ps.find("client_max_window_bits")
1027 .unwrap()
1028 .value
1029 .unwrap()
1030 .eq_bytes(b"10")
1031 );
1032 }
1033
1034 #[test]
1035 fn test_optional_params_edge_cases() {
1036 assert_eq!(po(b"").unwrap().1, 0);
1037 assert_eq!(po(b";;").unwrap().1, 2);
1038 assert_eq!(values(&po(b";a").unwrap().0), [(&b"a"[..], None)]);
1039 assert_eq!(
1040 values(&po(b";a;b").unwrap().0),
1041 [(&b"a"[..], None), (b"b", None)]
1042 );
1043 assert_eq!(po(b";a ;b").unwrap().1, 5);
1046 assert_eq!(po(b";a , b").unwrap().1, 2);
1047 assert_eq!(po(b";a b").unwrap().1, 2);
1048 assert_eq!(po(b";a\t").unwrap().1, 2);
1049 assert_eq!(po(b";a,").unwrap().1, 2);
1050 assert_eq!(po(b";a=").unwrap_err().kind(), ErrorKind::MissingValue);
1052 assert_eq!(po(b";a=;b").unwrap_err().kind(), ErrorKind::MissingValue);
1053 assert_eq!(po(b";a=,").unwrap_err().kind(), ErrorKind::MissingValue);
1054 let e = po(b";a =1").unwrap_err();
1055 assert_eq!((e.kind(), e.offset()), (ErrorKind::InvalidByte, 2));
1056 assert_eq!(po(b";a= 1").unwrap_err().kind(), ErrorKind::InvalidByte);
1057 assert_eq!(po(b";a\t=1").unwrap_err().kind(), ErrorKind::InvalidByte);
1058 assert_eq!(po(b";a\"x\"").unwrap_err().kind(), ErrorKind::MissingValue);
1060 assert_eq!(po(b";a@").unwrap_err().kind(), ErrorKind::NotToken);
1061 assert_eq!(po(b";a\x01").unwrap_err().kind(), ErrorKind::Control);
1062 assert_eq!(po(b";a\r\n").unwrap_err().kind(), ErrorKind::BareCr);
1063 assert_eq!(po(b";@").unwrap_err().kind(), ErrorKind::NotToken);
1064 assert_eq!(
1065 po(b";a=\"x").unwrap_err().kind(),
1066 ErrorKind::UnterminatedQuote
1067 );
1068 }
1069
1070 #[test]
1071 fn test_optional_params_duplicates_and_limits() {
1072 for dup in [&b";a;A"[..], b";a=1;a", b";a;a=1", b";a; b; A=\"x\""] {
1074 let e = po(dup).unwrap_err();
1075 assert_eq!(e.kind(), ErrorKind::DuplicateParameter, "{dup:?}");
1076 }
1077 let last = Limits::DEFAULT.duplicate_params(DuplicatePolicy::Last);
1078 let first = Limits::DEFAULT.duplicate_params(DuplicatePolicy::First);
1079 let (l, _) = parse_optional(b";a;A=2", &last).unwrap();
1080 let (f, _) = parse_optional(b";a;A=2", &first).unwrap();
1081 assert!(l.find("a").unwrap().value.unwrap().eq_bytes(b"2"));
1082 assert!(f.find("a").unwrap().value.is_none());
1083 assert_eq!(f.len(), 2);
1084 let upto = |n: usize| {
1085 (0..n)
1086 .map(|i| format!(";p{i}"))
1087 .collect::<Vec<_>>()
1088 .concat()
1089 };
1090 assert_eq!(po(upto(MAX_CHECKED_PARAMS).as_bytes()).unwrap().0.len(), 64);
1091 let over = upto(MAX_CHECKED_PARAMS + 1);
1092 let e = po(over.as_bytes()).unwrap_err();
1093 assert_eq!(
1094 (e.kind(), e.offset()),
1095 (ErrorKind::TooManyMembers, over.rfind(';').unwrap() + 1)
1096 );
1097 let bare = upto(257);
1098 assert_eq!(
1099 parse_optional(bare.as_bytes(), &last).unwrap_err().kind(),
1100 ErrorKind::TooManyMembers
1101 );
1102 }
1103
1104 #[test]
1105 fn test_optional_params_lookups_and_debug() {
1106 let (ps, _) = po(b";; a ;b=\"x;y\";token=\"s3cr3t\";").unwrap();
1107 assert_eq!(ps.raw(), b";; a ;b=\"x;y\";token=\"s3cr3t\";");
1108 assert_eq!(ps.find("A").map(|x| x.value), Some(None));
1109 assert!(ps.find("b").unwrap().value.unwrap().eq_bytes(b"x;y"));
1110 assert!(ps.contains("TOKEN") && !ps.contains("y") && !ps.contains(""));
1111 let d = format!("{ps:?}");
1112 assert_eq!(d, "OptionalParams([\"a\", \"b\", \"token\"])");
1113 assert!(!d.contains("s3cr3t"));
1114 }
1115
1116 mod reference {
1119 use super::super::*;
1120 use crate::text::{parse_word, skip_ows};
1121
1122 pub(super) fn parse<'a>(s: &'a [u8], limits: &Limits) -> Result<(Params<'a>, usize)> {
1123 let policy = limits.duplicate_params;
1124 let mut count: usize = 0;
1125 let mut used = 0usize;
1126 let mut seen: u64 = 0;
1127 loop {
1128 let ows = skip_ows(s.get(used..).unwrap_or(&[]));
1129 let semi = used + ows;
1130 if s.get(semi) != Some(&b';') {
1131 break;
1132 }
1133 let mut i = semi + 1;
1134 i += skip_ows(s.get(i..).unwrap_or(&[]));
1135 match s.get(i) {
1136 None | Some(b';') => {
1137 used = i;
1138 continue;
1139 }
1140 Some(&b) if !class::is_tchar(b) => {
1141 if b == b',' {
1144 used = semi + 1;
1145 break;
1146 }
1147 return err(
1148 if crate::scan::is_control(b) {
1149 control_kind(b)
1150 } else {
1151 ErrorKind::NotToken
1152 },
1153 i,
1154 );
1155 }
1156 Some(_) => {}
1157 }
1158 let name_start = i;
1159 let name_len = s
1160 .get(i..)
1161 .unwrap_or(&[])
1162 .iter()
1163 .take_while(|&&b| class::is_tchar(b))
1164 .count();
1165 let name = s.get(name_start..name_start + name_len).unwrap_or(&[]);
1166 i += name_len;
1167 match s.get(i) {
1168 Some(b'=') => i += 1,
1169 Some(&b) if is_ows(b) => {
1170 let after = i + skip_ows(s.get(i..).unwrap_or(&[]));
1171 if s.get(after) == Some(&b'=') {
1172 return err(ErrorKind::InvalidByte, i);
1173 }
1174 return err(ErrorKind::MissingValue, i);
1175 }
1176 Some(b'"') => return err(ErrorKind::MissingValue, i),
1177 Some(&b) if b != b';' && b != b',' && class::is_field_text(b) => {
1178 return err(ErrorKind::NotToken, i);
1179 }
1180 Some(&b) if !class::is_field_text(b) => return err(control_kind(b), i),
1181 _ => return err(ErrorKind::MissingValue, i),
1182 }
1183 let value_start = i;
1184 match s.get(i) {
1185 Some(&b) if is_ows(b) => return err(ErrorKind::InvalidByte, i),
1186 None | Some(b';' | b',') => return err(ErrorKind::MissingValue, i),
1187 _ => {}
1188 }
1189 let rest = s.get(i..).unwrap_or(&[]);
1190 let (_, n) = parse_word(rest).map_err(|e| match e.kind() {
1191 ErrorKind::Empty => crate::error::ParseError::new(
1192 control_or_invalid(rest.first().copied().unwrap_or(0)),
1193 value_start,
1194 ),
1195 _ => e.shifted(value_start),
1196 })?;
1197 i += n;
1198 count += 1;
1199 if count > usize::from(limits.params) {
1200 return err(ErrorKind::TooManyMembers, name_start);
1201 }
1202 if policy == DuplicatePolicy::Refuse {
1203 let bit = name_bit(name);
1204 if seen & bit != 0 {
1205 let earlier = Params {
1206 text: s.get(..used).unwrap_or(&[]),
1207 count: 0,
1208 policy,
1209 };
1210 if earlier.iter().any(|p| p.name.eq_ignore_ascii_case(name)) {
1211 return err(ErrorKind::DuplicateParameter, name_start);
1212 }
1213 }
1214 seen |= bit;
1215 }
1216 used = i;
1217 }
1218 Ok((
1219 Params {
1220 text: s.get(..used).unwrap_or(&[]),
1221 count: u32::try_from(count).unwrap_or(u32::MAX),
1222 policy,
1223 },
1224 used,
1225 ))
1226 }
1227
1228 pub(super) fn parse_optional(
1231 s: &[u8],
1232 limits: &Limits,
1233 ) -> Result<(std::vec::Vec<u8>, usize, usize)> {
1234 let refuse = limits.duplicate_params == DuplicatePolicy::Refuse;
1235 let max = if refuse {
1236 usize::from(limits.params).min(MAX_CHECKED_PARAMS)
1237 } else {
1238 usize::from(limits.params)
1239 };
1240 let mut seen: std::vec::Vec<&[u8]> = std::vec::Vec::new();
1241 let mut used = 0usize;
1242 loop {
1243 let semi = used + skip_ows(s.get(used..).unwrap_or(&[]));
1244 if s.get(semi) != Some(&b';') {
1245 break;
1246 }
1247 let mut i = semi + 1;
1248 i += skip_ows(s.get(i..).unwrap_or(&[]));
1249 let Ok((name, n)) = crate::text::parse_token(s.get(i..).unwrap_or(&[])) else {
1250 match s.get(i) {
1251 None | Some(b';') => used = i,
1252 Some(b',') => {
1253 used = semi + 1;
1254 break;
1255 }
1256 Some(&b) if crate::scan::is_control(b) => return err(control_kind(b), i),
1257 Some(_) => return err(ErrorKind::NotToken, i),
1258 }
1259 continue;
1260 };
1261 let name_start = i;
1262 i += n;
1263 match s.get(i) {
1264 Some(b'=') => {
1265 i += 1;
1266 match s.get(i) {
1267 Some(&b) if is_ows(b) => return err(ErrorKind::InvalidByte, i),
1268 None | Some(b';' | b',') => return err(ErrorKind::MissingValue, i),
1269 _ => {}
1270 }
1271 let rest = s.get(i..).unwrap_or(&[]);
1272 let (_, n) = parse_word(rest).map_err(|e| match e.kind() {
1273 ErrorKind::Empty => crate::error::ParseError::new(
1274 control_or_invalid(rest.first().copied().unwrap_or(0)),
1275 i,
1276 ),
1277 _ => e.shifted(i),
1278 })?;
1279 i += n;
1280 }
1281 None | Some(b';' | b',') => {}
1282 Some(&b) if is_ows(b) => {
1283 let after = i + skip_ows(s.get(i..).unwrap_or(&[]));
1284 if s.get(after) == Some(&b'=') {
1285 return err(ErrorKind::InvalidByte, i);
1286 }
1287 }
1288 Some(b'"') => return err(ErrorKind::MissingValue, i),
1289 Some(&b) if class::is_field_text(b) => return err(ErrorKind::NotToken, i),
1290 Some(&b) => return err(control_kind(b), i),
1291 }
1292 if seen.len() + 1 > max {
1293 return err(ErrorKind::TooManyMembers, name_start);
1294 }
1295 if refuse && seen.iter().any(|e| e.eq_ignore_ascii_case(name)) {
1296 return err(ErrorKind::DuplicateParameter, name_start);
1297 }
1298 seen.push(name);
1299 used = i;
1300 }
1301 Ok((s.get(..used).unwrap_or(&[]).to_vec(), seen.len(), used))
1302 }
1303 }
1304
1305 fn reference_optional_iter(raw: &[u8]) -> Vec<OptionalParam<'_>> {
1308 let mut out = Vec::new();
1309 let mut i = 0;
1310 loop {
1311 i += crate::text::skip_ows(raw.get(i..).unwrap_or(&[]));
1312 if raw.get(i) != Some(&b';') {
1313 return out;
1314 }
1315 i += 1;
1316 i += crate::text::skip_ows(raw.get(i..).unwrap_or(&[]));
1317 let Ok((name, n)) = crate::text::parse_token(raw.get(i..).unwrap_or(&[])) else {
1318 continue;
1319 };
1320 i += n;
1321 let value = if raw.get(i) == Some(&b'=') {
1322 let (value, n) = crate::text::parse_word(raw.get(i + 1..).unwrap_or(&[])).unwrap();
1323 i += 1 + n;
1324 Some(value)
1325 } else {
1326 None
1327 };
1328 out.push(OptionalParam { name, value });
1329 }
1330 }
1331
1332 fn param_text() -> impl Strategy<Value = Vec<u8>> {
1334 let piece = prop_oneof![
1335 Just(b";".to_vec()),
1336 Just(b" ".to_vec()),
1337 Just(b"\t".to_vec()),
1338 Just(b"=".to_vec()),
1339 Just(b",".to_vec()),
1340 Just(b"\"a\\\"b;c=d\"".to_vec()),
1341 Just(b"\"\\".to_vec()),
1342 Just(b"\r".to_vec()),
1343 Just(b"\x7f".to_vec()),
1344 "[a-cA-C]{1,3}".prop_map(String::into_bytes),
1345 "[0-9]{1,3}".prop_map(String::into_bytes),
1346 "[(){}@/]".prop_map(String::into_bytes),
1347 "; ?[a-cA-C]{1,2}=[0-9a-c]{1,2}".prop_map(String::into_bytes),
1348 "; ?[a-c]=\"[a-c;,= ]{0,3}\"".prop_map(String::into_bytes),
1349 ];
1350 prop::collection::vec(piece, 0..16).prop_map(|v| v.concat())
1351 }
1352
1353 fn outcome(
1354 r: Result<(Params<'_>, usize)>,
1355 ) -> core::result::Result<(Vec<u8>, usize, usize), (ErrorKind, usize)> {
1356 r.map(|(p, used)| (p.raw().to_vec(), p.len(), used))
1357 .map_err(|e| (e.kind(), e.offset()))
1358 }
1359
1360 fn reference_iter(raw: &[u8]) -> Vec<Param<'_>> {
1362 let mut out = Vec::new();
1363 let mut i = 0;
1364 loop {
1365 i += crate::text::skip_ows(raw.get(i..).unwrap_or(&[]));
1366 if raw.get(i) != Some(&b';') {
1367 return out;
1368 }
1369 i += 1;
1370 i += crate::text::skip_ows(raw.get(i..).unwrap_or(&[]));
1371 let Ok((name, n)) = crate::text::parse_token(raw.get(i..).unwrap_or(&[])) else {
1372 continue;
1373 };
1374 i += n + 1;
1375 let (value, n) = crate::text::parse_word(raw.get(i..).unwrap_or(&[])).unwrap();
1376 i += n;
1377 out.push(Param { name, value });
1378 }
1379 }
1380
1381 proptest::proptest! {
1382 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(4096))]
1383
1384 #[test]
1385 fn test_parse_agrees_with_reference(v in param_text()) {
1386 for policy in [DuplicatePolicy::Refuse, DuplicatePolicy::First, DuplicatePolicy::Last] {
1387 let limits = Limits::DEFAULT.duplicate_params(policy);
1388 prop_assert_eq!(outcome(parse(&v, &limits)), outcome(reference::parse(&v, &limits)));
1389 }
1390 }
1391
1392 #[test]
1393 fn test_iter_and_get_agree_with_checked_reads(v in param_text(), name in "[a-cA-C=; \"]{0,4}") {
1394 for policy in [DuplicatePolicy::Refuse, DuplicatePolicy::First, DuplicatePolicy::Last] {
1395 let limits = Limits::DEFAULT.duplicate_params(policy);
1396 let Ok((p, _)) = parse(&v, &limits) else { continue };
1397 let all: Vec<Param<'_>> = p.iter().collect();
1398 prop_assert_eq!(&all, &reference_iter(p.raw()));
1399 prop_assert_eq!(all.len(), p.len());
1400 let mut matching = all.iter().filter(|x| x.name.eq_ignore_ascii_case(name.as_bytes()));
1401 let expected = if policy == DuplicatePolicy::Last { matching.next_back() } else { matching.next() };
1402 prop_assert_eq!(p.get(&name), expected.map(|x| x.value));
1403 for x in &all {
1404 let n = core::str::from_utf8(x.name).unwrap();
1405 let mut same = all.iter().filter(|y| y.name.eq_ignore_ascii_case(x.name));
1406 let expected = if policy == DuplicatePolicy::Last { same.next_back() } else { same.next() };
1407 prop_assert_eq!(p.get(n), expected.map(|y| y.value));
1408 }
1409 }
1410 }
1411
1412 #[test]
1413 fn test_parse_optional_agrees_with_reference(v in param_text()) {
1414 for policy in [DuplicatePolicy::Refuse, DuplicatePolicy::First, DuplicatePolicy::Last] {
1415 let limits = Limits::DEFAULT.duplicate_params(policy);
1416 let got = parse_optional(&v, &limits)
1417 .map(|(p, used)| (p.raw().to_vec(), p.len(), used))
1418 .map_err(|e| (e.kind(), e.offset()));
1419 let want = reference::parse_optional(&v, &limits).map_err(|e| (e.kind(), e.offset()));
1420 prop_assert_eq!(got, want);
1421 }
1422 }
1423
1424 #[test]
1425 fn test_parse_optional_extends_parse(v in param_text()) {
1426 for policy in [DuplicatePolicy::Refuse, DuplicatePolicy::First, DuplicatePolicy::Last] {
1429 let limits = Limits::DEFAULT.duplicate_params(policy);
1430 let opt = parse_optional(&v, &limits);
1431 match parse(&v, &limits) {
1432 Ok((p, used)) => {
1433 let (o, o_used) = opt.unwrap();
1434 prop_assert_eq!((o.raw(), o.len(), o_used), (p.raw(), p.len(), used));
1435 let with: Vec<OptionalParam<'_>> = p.iter()
1436 .map(|x| OptionalParam { name: x.name, value: Some(x.value) })
1437 .collect();
1438 prop_assert_eq!(o.iter().collect::<Vec<_>>(), with);
1439 }
1440 Err(e) if e.kind() != ErrorKind::MissingValue => {
1441 let o = opt.unwrap_err();
1442 prop_assert_eq!((o.kind(), o.offset()), (e.kind(), e.offset()));
1443 }
1444 Err(_) => {}
1445 }
1446 }
1447 }
1448
1449 #[test]
1450 fn test_optional_iter_and_find_agree_with_checked_reads(v in param_text(), name in "[a-cA-C=; \"]{0,4}") {
1451 for policy in [DuplicatePolicy::Refuse, DuplicatePolicy::First, DuplicatePolicy::Last] {
1452 let limits = Limits::DEFAULT.duplicate_params(policy);
1453 let Ok((p, _)) = parse_optional(&v, &limits) else { continue };
1454 let all: Vec<OptionalParam<'_>> = p.iter().collect();
1455 prop_assert_eq!(&all, &reference_optional_iter(p.raw()));
1456 prop_assert_eq!(all.len(), p.len());
1457 let mut matching = all.iter().filter(|x| x.name.eq_ignore_ascii_case(name.as_bytes()));
1458 let expected = if policy == DuplicatePolicy::Last { matching.next_back() } else { matching.next() };
1459 prop_assert_eq!(p.find(&name), expected.copied());
1460 prop_assert_eq!(p.contains(&name), expected.is_some());
1461 }
1462 }
1463 }
1464}