Skip to main content

parse_net/
param.rs

1//! Parameters: `*( OWS ";" OWS [ parameter ] )` (RFC 9110 section 5.6.6).
2//!
3//! # Examples
4//!
5//! ```
6//! use parse_net::{param, Limits};
7//!
8//! let (p, used) = param::parse(b"; charset=utf-8;format=\"flowed\" , next", &Limits::DEFAULT)?;
9//! assert_eq!(used, 31);
10//! assert!(p.get("Charset").is_some_and(|v| v.eq_bytes(b"utf-8")));
11//! assert_eq!(format!("{p:?}"), "Params([\"charset\", \"format\"])");
12//! # Ok::<(), parse_net::ParseError>(())
13//! ```
14
15use 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/// One parameter: a name and a value.
26///
27/// # Examples
28///
29/// ```
30/// use parse_net::{param, Limits, Param, Word};
31///
32/// let (p, _) = param::parse(b";charset=utf-8", &Limits::DEFAULT)?;
33/// assert_eq!(p.iter().next(), Some(Param { name: b"charset", value: Word::Token(b"utf-8") }));
34/// # Ok::<(), parse_net::ParseError>(())
35/// ```
36#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
37pub struct Param<'a> {
38    /// The name as sent (compare it ASCII case-insensitively).
39    pub name: &'a [u8],
40    /// The value.
41    pub value: Word<'a>,
42}
43
44/// A small filter over parameter names, so a repeated name is searched for
45/// only when one could exist. Bounded: at most `max_params` names are seen.
46#[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
58/// Parses parameters at the start of `s`.
59///
60/// `s` starts at the first `;` (optionally preceded by OWS) or is empty.
61/// Parsing continues as long as the grammar does; the view and the number of
62/// bytes used are returned (OWS after the last parameter is not used), and
63/// whatever follows is the caller's to check. Empty parameters (`;;`, a
64/// trailing `;`) are allowed, as the grammar says. Whitespace around `=` is
65/// not (BWS is not part of this grammar).
66///
67/// # Errors
68///
69/// [`ErrorKind::NotToken`] for a bad name; [`ErrorKind::MissingValue`] for a
70/// name with no `=` or no value; [`ErrorKind::InvalidByte`] for whitespace
71/// around `=`; the quoted-string errors; [`ErrorKind::DuplicateParameter`]
72/// under [`DuplicatePolicy::Refuse`]; [`ErrorKind::TooManyMembers`] beyond
73/// [`Limits::max_params`].
74///
75/// # Examples
76///
77/// ```
78/// use parse_net::{param, ErrorKind, Limits};
79///
80/// let dup = param::parse(b";a=1;A=2", &Limits::DEFAULT).unwrap_err();
81/// assert_eq!((dup.kind(), dup.offset()), (ErrorKind::DuplicateParameter, 5));
82/// assert_eq!(param::parse(b";a =1", &Limits::DEFAULT).unwrap_err().kind(), ErrorKind::InvalidByte);
83/// ```
84pub 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                // OWS after an empty parameter followed by a list separator
104                // or the end belongs to the caller.
105                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/// Validated parameters. Iterating them cannot fail.
200///
201/// `Debug` prints the parameter names only: values can be secrets.
202///
203/// # Examples
204///
205/// ```
206/// use parse_net::{param, Limits};
207///
208/// let (p, used) = param::parse(b";q=1;level=\"2\"", &Limits::DEFAULT)?;
209/// assert_eq!((p.len(), used), (2, 14));
210/// assert!(p.get("level").is_some_and(|v| v.eq_bytes(b"2")));
211/// # Ok::<(), parse_net::ParseError>(())
212/// ```
213#[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    /// Every parameter, in order (with `First` or `Last`, duplicates
222    /// included).
223    ///
224    /// # Examples
225    ///
226    /// ```
227    /// use parse_net::{param, Limits};
228    ///
229    /// let (p, _) = param::parse(b";a=1; B=2", &Limits::DEFAULT)?;
230    /// let names: Vec<&[u8]> = p.iter().map(|p| p.name).collect();
231    /// assert_eq!(names, [&b"a"[..], b"B"]);
232    /// # Ok::<(), parse_net::ParseError>(())
233    /// ```
234    #[must_use]
235    pub fn iter(&self) -> ParamIter<'a> {
236        ParamIter { rest: self.text }
237    }
238
239    /// The value of the parameter named `name` (ASCII case-insensitive): the
240    /// first match, or the last under [`DuplicatePolicy::Last`].
241    ///
242    /// # Examples
243    ///
244    /// ```
245    /// use parse_net::{param, Limits};
246    ///
247    /// let (p, _) = param::parse(b";charset=UTF-8", &Limits::DEFAULT)?;
248    /// assert!(p.get("CHARSET").is_some_and(|v| v.eq_bytes(b"UTF-8")));
249    /// assert!(p.get("q").is_none());
250    /// # Ok::<(), parse_net::ParseError>(())
251    /// ```
252    #[must_use]
253    pub fn get(&self, name: &str) -> Option<Word<'a>> {
254        let name = name.as_bytes();
255        // An exact compare first: names are usually sent in the case asked for.
256        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    /// The parameters before the first one named `name` (ASCII
268    /// case-insensitive), and that parameter; all of them and `None` when no
269    /// parameter has the name. Used to split media-type parameters from
270    /// `q` and the `accept-ext` after it.
271    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                // `p.name` points into `self.text`; the distance is its offset.
275                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    /// The number of parameters.
290    ///
291    /// # Examples
292    ///
293    /// ```
294    /// use parse_net::{param, Limits};
295    ///
296    /// assert_eq!(param::parse(b";a=1;;b=2;", &Limits::DEFAULT)?.0.len(), 2);
297    /// # Ok::<(), parse_net::ParseError>(())
298    /// ```
299    #[must_use]
300    pub const fn len(&self) -> usize {
301        self.count as usize
302    }
303
304    /// Whether there are no parameters.
305    ///
306    /// # Examples
307    ///
308    /// ```
309    /// use parse_net::{param, Limits};
310    ///
311    /// assert!(param::parse(b"", &Limits::DEFAULT)?.0.is_empty());
312    /// assert!(!param::parse(b";a=1", &Limits::DEFAULT)?.0.is_empty());
313    /// # Ok::<(), parse_net::ParseError>(())
314    /// ```
315    #[must_use]
316    pub const fn is_empty(&self) -> bool {
317        self.count == 0
318    }
319
320    /// The validated text, from the first `;` to the end of the last
321    /// parameter.
322    ///
323    /// # Examples
324    ///
325    /// ```
326    /// use parse_net::{param, Limits};
327    ///
328    /// let (p, _) = param::parse(b";a=1 ;b=2 , next", &Limits::DEFAULT)?;
329    /// assert_eq!(p.raw(), b";a=1 ;b=2");
330    /// # Ok::<(), parse_net::ParseError>(())
331    /// ```
332    #[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/// The parameters of a validated [`Params`].
352///
353/// # Examples
354///
355/// ```
356/// use parse_net::{param, Limits};
357///
358/// let (p, _) = param::parse(b";a=1;b=2", &Limits::DEFAULT)?;
359/// let mut it = p.iter();
360/// assert_eq!(it.next().map(|p| p.name), Some(&b"a"[..]));
361/// assert_eq!(it.next().map(|p| p.name), Some(&b"b"[..]));
362/// assert!(it.next().is_none());
363/// # Ok::<(), parse_net::ParseError>(())
364/// ```
365#[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            // Validated text: OWS ";" OWS [ name "=" word ] ...
376            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}