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 crate::scan::is_control(b) {
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 crate::scan::is_control(b) {
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 pub(crate) fn split_at_name(&self, name: &[u8]) -> (Params<'a>, Option<Param<'a>>) {
226 for (index, p) in self.iter().enumerate() {
227 if p.name.eq_ignore_ascii_case(name) {
228 let off = (p.name.as_ptr() as usize).saturating_sub(self.text.as_ptr() as usize);
230 let head = self.text.get(..off).unwrap_or(&[]);
231 let semi = head.iter().rposition(|&b| b == b';').unwrap_or(0);
232 let before = Params {
233 text: self.text.get(..semi).unwrap_or(&[]),
234 count: u32::try_from(index).unwrap_or(u32::MAX),
235 policy: self.policy,
236 };
237 return (before, Some(p));
238 }
239 }
240 (*self, None)
241 }
242
243 #[must_use]
245 pub const fn len(&self) -> usize {
246 self.count as usize
247 }
248
249 #[must_use]
251 pub const fn is_empty(&self) -> bool {
252 self.count == 0
253 }
254
255 #[must_use]
258 pub const fn raw(&self) -> &'a [u8] {
259 self.text
260 }
261}
262
263impl fmt::Debug for Params<'_> {
264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265 f.write_str("Params(")?;
266 f.debug_list()
267 .entries(
268 self.iter()
269 .map(|p| core::str::from_utf8(p.name).unwrap_or("?")),
270 )
271 .finish()?;
272 f.write_str(")")
273 }
274}
275
276#[derive(Clone, Debug)]
278pub struct ParamIter<'a> {
279 rest: &'a [u8],
280}
281
282impl<'a> Iterator for ParamIter<'a> {
283 type Item = Param<'a>;
284
285 fn next(&mut self) -> Option<Param<'a>> {
286 loop {
287 let s = self.rest;
289 let semi = s.iter().position(|&b| b == b';')?;
290 let after = semi + 1;
291 let start = after + skip_ows(s.get(after..).unwrap_or(&[]));
292 let tail = s.get(start..).unwrap_or(&[]);
293 let name_len = tail.iter().take_while(|&&b| class::is_tchar(b)).count();
294 if name_len == 0 {
295 self.rest = tail;
296 continue;
297 }
298 let name = tail.get(..name_len).unwrap_or(&[]);
299 let value_text = tail.get(name_len + 1..).unwrap_or(&[]);
300 let Ok((value, n)) = parse_word(value_text) else {
301 self.rest = &[];
302 return None;
303 };
304 self.rest = value_text.get(n..).unwrap_or(&[]);
305 return Some(Param { name, value });
306 }
307 }
308}
309
310#[cfg(test)]
311mod tests {
312 use std::{format, vec::Vec};
313
314 use super::*;
315
316 fn p(s: &[u8]) -> Result<(Params<'_>, usize)> {
317 parse(s, &Limits::DEFAULT)
318 }
319
320 fn names<'a>(ps: &Params<'a>) -> Vec<&'a [u8]> {
321 ps.iter().map(|x| x.name).collect()
322 }
323
324 #[test]
325 fn test_params_edge_cases() {
326 assert_eq!(p(b"").unwrap().1, 0);
327 assert!(p(b";").unwrap().0.is_empty());
328 assert_eq!(p(b";").unwrap().1, 1);
329 assert_eq!(p(b";;").unwrap().1, 2);
330 let (ps, used) = p(b"; a=b").unwrap();
331 assert_eq!((used, names(&ps)), (5, [&b"a"[..]].to_vec()));
332 assert_eq!(p(b";a=").unwrap_err().kind(), ErrorKind::MissingValue);
333 assert_eq!(p(b";a").unwrap_err().kind(), ErrorKind::MissingValue);
334 assert_eq!(p(b";a;b=c").unwrap_err().kind(), ErrorKind::MissingValue);
335 assert_eq!(p(b";a =b").unwrap_err().kind(), ErrorKind::InvalidByte);
336 assert_eq!(p(b";a= b").unwrap_err().kind(), ErrorKind::InvalidByte);
337 assert_eq!(p(b";@=b").unwrap_err().kind(), ErrorKind::NotToken);
338 assert_eq!(p(b";a@=b").unwrap_err().kind(), ErrorKind::NotToken);
339 assert_eq!(p(b";a=\"\"").unwrap().0.get("a").map(|w| w.len()), Some(0));
340 assert!(
341 p(b";a=\"x\\\"y\"")
342 .unwrap()
343 .0
344 .get("a")
345 .unwrap()
346 .eq_bytes(b"x\"y")
347 );
348 assert_eq!(
349 p(b";a=\"x").unwrap_err().kind(),
350 ErrorKind::UnterminatedQuote
351 );
352 assert_eq!(p(b";a=b\rc").unwrap().1, 4);
353 assert_eq!(p(b";a=\x01").unwrap_err().kind(), ErrorKind::Control);
354 }
355
356 #[test]
357 fn test_params_stop_at_list_separator_and_trailing_ows() {
358 let (ps, used) = p(b";a=1 , b").unwrap();
359 assert_eq!((used, ps.len()), (4, 1));
360 let (_, used) = p(b";a=1; ,b").unwrap();
361 assert_eq!(used, 5);
362 let (_, used) = p(b" ;a=1 x").unwrap();
363 assert_eq!(used, 5);
364 }
365
366 #[test]
367 fn test_params_duplicate_refused_case_insensitive() {
368 let e = p(b";A=b;a=c").unwrap_err();
369 assert_eq!((e.kind(), e.offset()), (ErrorKind::DuplicateParameter, 5));
370 assert!(p(b";ab=1;ba=2;aa=3;bb=4").is_ok());
371 }
372
373 #[test]
374 fn test_params_first_and_last_policies() {
375 let first = Limits::DEFAULT.duplicate_params(DuplicatePolicy::First);
376 let last = Limits::DEFAULT.duplicate_params(DuplicatePolicy::Last);
377 let (a, _) = parse(b";a=1;A=2", &first).unwrap();
378 let (b, _) = parse(b";a=1;A=2", &last).unwrap();
379 assert!(a.get("a").unwrap().eq_bytes(b"1"));
380 assert!(b.get("a").unwrap().eq_bytes(b"2"));
381 assert_eq!(a.len(), 2);
382 }
383
384 #[test]
385 fn test_params_count_limit() {
386 let mut v = Vec::new();
387 for i in 0..257 {
388 v.extend_from_slice(format!(";p{i}=v").as_bytes());
389 }
390 let cut = v.len() - format!(";p{}=v", 256).len();
391 assert_eq!(p(&v[..cut]).unwrap().0.len(), 256);
392 assert_eq!(p(&v).unwrap_err().kind(), ErrorKind::TooManyMembers);
393 }
394
395 #[test]
396 fn test_params_debug_prints_names_only() {
397 let (ps, _) = p(b";user=alice;token=\"s3cr3t\"").unwrap();
398 let d = format!("{ps:?}");
399 assert_eq!(d, "Params([\"user\", \"token\"])");
400 assert!(!d.contains("s3cr3t") && !d.contains("alice"));
401 }
402
403 #[test]
404 fn test_params_iter_skips_empty_parameters() {
405 let (ps, _) = p(b";; a=1 ;;b=\"x;y\";").unwrap();
406 assert_eq!(names(&ps), [&b"a"[..], b"b"]);
407 assert!(ps.get("b").unwrap().eq_bytes(b"x;y"));
408 assert_eq!(ps.raw(), b";; a=1 ;;b=\"x;y\";");
409 }
410}