Access headers as key/values #24

Merged
quentin merged 8 commits from headers_map into main 2023-08-30 17:50:26 +00:00
Showing only changes of commit ba59b037ef - Show all commits

View file

@ -5,8 +5,8 @@ use nom::{
branch::alt, branch::alt,
bytes::complete::{tag, tag_no_case, take_while1}, bytes::complete::{tag, tag_no_case, take_while1},
character::complete::space0, character::complete::space0,
combinator::map, combinator::{into, map},
multi::{fold_many0}, multi::{fold_many0, many0},
sequence::{pair, terminated, tuple}, sequence::{pair, terminated, tuple},
IResult, IResult,
}; };
@ -20,6 +20,40 @@ pub enum CompField<'a, T> {
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Kv<'a>(pub &'a [u8], pub Unstructured<'a>); pub struct Kv<'a>(pub &'a [u8], pub Unstructured<'a>);
impl<'a> From<(&'a [u8], Unstructured<'a>)> for Kv<'a> {
fn from(pair: (&'a [u8], Unstructured<'a>)) -> Self {
Self(pair.0, pair.1)
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum Field<'a> {
Good(Kv<'a>),
Bad(&'a [u8]),
}
impl<'a> From<Kv<'a>> for Field<'a> {
fn from(kv: Kv<'a>) -> Self {
Self::Good(kv)
}
}
impl<'a> From<&'a [u8]> for Field<'a> {
fn from(bad: &'a [u8]) -> Self {
Self::Bad(bad)
}
}
/// Parse headers as key/values
pub fn header_kv(input: &[u8]) -> IResult<&[u8], Vec<Field>> {
terminated(
many0(
alt((
into(opt_field),
into(foldable_line),
))
),
obs_crlf
)(input)
}
pub fn header<'a, T>( pub fn header<'a, T>(
@ -30,7 +64,7 @@ pub fn header<'a, T>(
fold_many0( fold_many0(
alt(( alt((
map(fx, CompField::Known), map(fx, CompField::Known),
map(opt_field, |(k, v)| CompField::Unknown(Kv(k, v))), map(opt_field, CompField::Unknown),
map(foldable_line, CompField::Bad), map(foldable_line, CompField::Bad),
)), )),
|| (Vec::<T>::new(), Vec::<Kv>::new(), Vec::<&'a [u8]>::new()), || (Vec::<T>::new(), Vec::<Kv>::new(), Vec::<&'a [u8]>::new()),
@ -52,6 +86,13 @@ pub fn field_name<'a>(name: &'static [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [
move |input| terminated(tag_no_case(name), tuple((space0, tag(b":"), space0)))(input) move |input| terminated(tag_no_case(name), tuple((space0, tag(b":"), space0)))(input)
} }
pub fn field_any(input: &[u8]) -> IResult<&[u8], &[u8]> {
terminated(
take_while1(|c| (0x21..=0x7E).contains(&c) && c != 0x3A),
tuple((space0, tag(b":"), space0)),
)(input)
}
/// Optional field /// Optional field
/// ///
/// ```abnf /// ```abnf
@ -61,15 +102,12 @@ pub fn field_name<'a>(name: &'static [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [
/// %d59-126 ; characters not including /// %d59-126 ; characters not including
/// ; ":". /// ; ":".
/// ``` /// ```
pub fn opt_field(input: &[u8]) -> IResult<&[u8], (&[u8], Unstructured)> { pub fn opt_field(input: &[u8]) -> IResult<&[u8], Kv> {
terminated( terminated(
pair( into(pair(
terminated( field_any,
take_while1(|c| (0x21..=0x7E).contains(&c) && c != 0x3A),
tuple((space0, tag(b":"), space0)),
),
unstructured, unstructured,
), )),
obs_crlf, obs_crlf,
)(input) )(input)
} }