Access headers as key/values #24

Merged
quentin merged 8 commits from headers_map into main 2023-08-30 17:50:26 +00:00
5 changed files with 80 additions and 13 deletions
Showing only changes of commit 9b828ad6ad - Show all commits

View file

@ -1,3 +1,4 @@
use std::fmt;
use nom::{
branch::alt,
bytes::complete::{tag, take_while1},
@ -11,13 +12,21 @@ use nom::{
use crate::text::whitespace::{foldable_line, obs_crlf};
use crate::text::misc_token::unstructured;
#[derive(Debug, PartialEq, Clone)]
#[derive(PartialEq, Clone)]
pub struct Kv2<'a>(pub &'a [u8], pub &'a [u8]);
impl<'a> From<(&'a [u8], &'a [u8])> for Kv2<'a> {
fn from(pair: (&'a [u8], &'a [u8])) -> Self {
Self(pair.0, pair.1)
}
}
impl<'a> fmt::Debug for Kv2<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_tuple("header::Kv2")
.field(&String::from_utf8_lossy(self.0))
.field(&String::from_utf8_lossy(self.1))
.finish()
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum Field<'a> {

View file

@ -10,6 +10,7 @@ pub mod mechanism;
/// Content-Type representation
pub mod r#type;
use std::fmt;
use std::marker::PhantomData;
use crate::imf::identification::MessageID;
@ -55,15 +56,27 @@ impl<'a, T: WithDefaultType> From<AnyMIMEWithDefault<'a, T>> for AnyMIME<'a> {
}
}
#[derive(Debug, PartialEq, Default, Clone)]
#[derive(PartialEq, Default, Clone)]
pub struct NaiveMIME<'a> {
pub ctype: Option<NaiveType<'a>>,
pub transfer_encoding: Mechanism<'a>,
pub id: Option<MessageID<'a>>,
pub description: Option<Unstructured<'a>>,
pub fields: Vec<header::Field<'a>>,
pub kv: Vec<header::Field<'a>>,
pub raw: &'a [u8],
}
impl<'a> fmt::Debug for NaiveMIME<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("NaiveMime")
.field("ctype", &self.ctype)
.field("transfer_encoding", &self.transfer_encoding)
.field("id", &self.id)
.field("description", &self.description)
.field("kv", &self.kv)
.field("raw", &String::from_utf8_lossy(self.raw))
.finish()
}
}
impl<'a> FromIterator<Content<'a>> for NaiveMIME<'a> {
fn from_iter<I: IntoIterator<Item = Content<'a>>>(it: I) -> Self {
@ -83,8 +96,8 @@ impl<'a> FromIterator<Content<'a>> for NaiveMIME<'a> {
}
impl<'a> NaiveMIME<'a> {
pub fn with_fields(mut self, fields: Vec<header::Field<'a>>) -> Self {
self.fields = fields; self
pub fn with_kv(mut self, fields: Vec<header::Field<'a>>) -> Self {
self.kv = fields; self
}
pub fn with_raw(mut self, raw: &'a [u8]) -> Self {
self.raw = raw; self

View file

@ -1,3 +1,4 @@
use std::fmt;
use nom::{
bytes::complete::tag,
combinator::{map, opt},
@ -12,12 +13,21 @@ use crate::text::words::mime_atom;
use crate::mime::{AnyMIME, MIME, NaiveMIME};
// --------- NAIVE TYPE
#[derive(Debug, PartialEq, Clone)]
#[derive(PartialEq, Clone)]
pub struct NaiveType<'a> {
pub main: &'a [u8],
pub sub: &'a [u8],
pub params: Vec<Parameter<'a>>,
}
impl<'a> fmt::Debug for NaiveType<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("mime::NaiveType")
.field("main", &String::from_utf8_lossy(self.main))
.field("sub", &String::from_utf8_lossy(self.sub))
.field("params", &self.params)
.finish()
}
}
impl<'a> NaiveType<'a> {
pub fn to_type(&self) -> AnyType {
self.into()
@ -30,11 +40,20 @@ pub fn naive_type(input: &[u8]) -> IResult<&[u8], NaiveType> {
)(input)
}
#[derive(Debug, PartialEq, Clone)]
#[derive(PartialEq, Clone)]
pub struct Parameter<'a> {
pub name: &'a [u8],
pub value: MIMEWord<'a>,
}
impl<'a> fmt::Debug for Parameter<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("mime::Parameter")
.field("name", &String::from_utf8_lossy(self.name))
.field("value", &self.value)
.finish()
}
}
pub fn parameter(input: &[u8]) -> IResult<&[u8], Parameter> {
map(
tuple((mime_atom, tag(b"="), mime_word)),

View file

@ -1,3 +1,4 @@
use std::fmt;
use nom::IResult;
use crate::header;
@ -8,13 +9,23 @@ use crate::text::boundary::{boundary, Delimiter};
use crate::pointers;
//--- Multipart
#[derive(Debug, PartialEq)]
#[derive(PartialEq)]
pub struct Multipart<'a> {
pub mime: mime::MIME<'a, mime::r#type::Multipart>,
pub children: Vec<AnyPart<'a>>,
pub raw_part_inner: &'a [u8],
pub raw_part_outer: &'a [u8],
}
impl<'a> fmt::Debug for Multipart<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("part::Multipart")
.field("mime", &self.mime)
.field("children", &self.children)
.field("raw_part_inner", &String::from_utf8_lossy(self.raw_part_inner))
.field("raw_part_outer", &String::from_utf8_lossy(self.raw_part_outer))
.finish()
}
}
impl<'a> Multipart<'a> {
pub fn preamble(&self) -> &'a [u8] {
pointers::parsed(self.raw_part_outer, self.raw_part_inner)
@ -83,7 +94,7 @@ pub fn multipart<'a>(
.collect::<mime::NaiveMIME>();
let mime = mime
.with_fields(fields)
.with_kv(fields)
.with_raw(raw_hdrs);
(input_eom, mime)
@ -113,7 +124,7 @@ pub fn multipart<'a>(
//--- Message
#[derive(Debug, PartialEq)]
#[derive(PartialEq)]
pub struct Message<'a> {
pub mime: mime::MIME<'a, mime::r#type::DeductibleMessage>,
pub imf: imf::Imf<'a>,
@ -123,6 +134,18 @@ pub struct Message<'a> {
pub raw_headers: &'a [u8],
pub raw_body: &'a [u8],
}
impl<'a> fmt::Debug for Message<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("part::Message")
.field("mime", &self.mime)
.field("imf", &self.imf)
.field("child", &self.child)
.field("raw_part", &String::from_utf8_lossy(self.raw_part))
.field("raw_headers", &String::from_utf8_lossy(self.raw_headers))
.field("raw_body", &String::from_utf8_lossy(self.raw_body))
.finish()
}
}
pub fn message<'a>(
m: mime::MIME<'a, mime::r#type::DeductibleMessage>,
@ -142,7 +165,7 @@ pub fn message<'a>(
let (naive_mime, imf) = part::field::split_and_build(&headers);
// interpret headers to choose a mime type
let in_mime = naive_mime.with_fields(headers).with_raw(raw_headers).to_interpreted::<mime::WithGenericDefault>().into();
let in_mime = naive_mime.with_kv(headers).with_raw(raw_headers).to_interpreted::<mime::WithGenericDefault>().into();
//---------------
// parse a part following this mime specification
@ -256,6 +279,9 @@ It DOES end with a linebreak.
]
}),
raw: &b"Content-type: text/plain; charset=us-ascii\n\n"[..],
kv: vec![
header::Field::Good(header::Kv2(&b"Content-type"[..], &b"text/plain; charset=us-ascii"[..]))
],
..mime::NaiveMIME::default()
},
},

View file

@ -14,7 +14,7 @@ impl<'a> fmt::Debug for Text<'a> {
.field("mime", &self.mime)
.field(
"body",
&format_args!("\"{}\"", String::from_utf8_lossy(self.body)),
&String::from_utf8_lossy(self.body),
)
.finish()
}
@ -32,7 +32,7 @@ impl<'a> fmt::Debug for Binary<'a> {
.field("mime", &self.mime)
.field(
"body",
&format_args!("\"{}\"", String::from_utf8_lossy(self.body)),
&String::from_utf8_lossy(self.body),
)
.finish()
}