1mod builder;
8mod classify;
9mod delimiter;
10mod header_block;
11
12#[cfg(test)]
13mod tests;
14
15pub(crate) use builder::Frame;
16
17use crate::{
18 HeaderForm, HeaderName, Message, MessageBuffers,
19 header_name::{FIRST_VENDOR, HeaderId, KNOWN_NAMES, OTHER_ID},
20 scan::Kernel,
21 store::MessageData,
22};
23use builder::Builder;
24use std::borrow::Cow;
25
26const FIRST_VENDOR_ID: usize = FIRST_VENDOR as usize;
27const CONTENT_TYPE: u16 = HeaderId::ContentType as u16;
28const CONTENT_DISPOSITION: u16 = HeaderId::ContentDisposition as u16;
29const CONTENT_TRANSFER_ENCODING: u16 = HeaderId::ContentTransferEncoding as u16;
30const DEFAULT_MAX_DEPTH: u32 = 64;
31const DEFAULT_MAX_PARTS: u32 = 10_000;
32const DEFAULT_MAX_ENCODED_NESTING: u32 = 3;
33
34const TEXT: [HeaderId; 5] = [
35 HeaderId::Subject,
36 HeaderId::Comments,
37 HeaderId::ContentDescription,
38 HeaderId::ContentLocation,
39 HeaderId::ContentTransferEncoding,
40];
41
42const ADDRESSES: [HeaderId; 18] = [
43 HeaderId::From,
44 HeaderId::To,
45 HeaderId::Cc,
46 HeaderId::Bcc,
47 HeaderId::ReplyTo,
48 HeaderId::Sender,
49 HeaderId::ResentTo,
50 HeaderId::ResentFrom,
51 HeaderId::ResentBcc,
52 HeaderId::ResentCc,
53 HeaderId::ResentSender,
54 HeaderId::ListArchive,
55 HeaderId::ListHelp,
56 HeaderId::ListId,
57 HeaderId::ListOwner,
58 HeaderId::ListPost,
59 HeaderId::ListSubscribe,
60 HeaderId::ListUnsubscribe,
61];
62
63const DATES: [HeaderId; 2] = [HeaderId::Date, HeaderId::ResentDate];
64
65const MESSAGE_IDS: [HeaderId; 6] = [
66 HeaderId::MessageId,
67 HeaderId::References,
68 HeaderId::InReplyTo,
69 HeaderId::ReturnPath,
70 HeaderId::ContentId,
71 HeaderId::ResentMessageId,
72];
73
74const COMMA_LISTS: [HeaderId; 2] = [HeaderId::Keywords, HeaderId::ContentLanguage];
75
76const CONTENT_TYPES: [HeaderId; 2] = [HeaderId::ContentType, HeaderId::ContentDisposition];
77
78const fn assign(
79 mut forms: [HeaderForm; KNOWN_NAMES],
80 ids: &[HeaderId],
81 form: HeaderForm,
82) -> [HeaderForm; KNOWN_NAMES] {
83 let mut index = 0;
84 while index < ids.len() {
85 forms[ids[index] as usize] = form;
86 index += 1;
87 }
88 forms
89}
90
91const DEFAULT_FORMS: [HeaderForm; KNOWN_NAMES] = {
92 let forms = [HeaderForm::Raw; KNOWN_NAMES];
93 let forms = assign(forms, &TEXT, HeaderForm::Text);
94 let forms = assign(forms, &ADDRESSES, HeaderForm::Addresses);
95 let forms = assign(forms, &DATES, HeaderForm::Date);
96 let forms = assign(forms, &MESSAGE_IDS, HeaderForm::MessageIds);
97 let forms = assign(forms, &COMMA_LISTS, HeaderForm::CommaList);
98 let forms = assign(forms, &[HeaderId::Received], HeaderForm::Received);
99 assign(forms, &CONTENT_TYPES, HeaderForm::ContentType)
100};
101
102#[derive(Debug, Clone, PartialEq, Eq)]
123pub struct MessageParser {
124 forms: [HeaderForm; KNOWN_NAMES],
125 configured_vendor: Vec<u16>,
126 custom: Vec<(Box<str>, HeaderForm)>,
127 unknown: HeaderForm,
128 max_depth: u32,
129 max_parts: u32,
130 max_encoded_nesting: u32,
131 kernel: Kernel,
132}
133
134impl Default for MessageParser {
135 fn default() -> Self {
136 MessageParser::new()
137 }
138}
139
140impl MessageParser {
141 pub fn new() -> Self {
146 MessageParser {
147 forms: DEFAULT_FORMS,
148 configured_vendor: Vec::new(),
149 custom: Vec::new(),
150 unknown: HeaderForm::Raw,
151 max_depth: DEFAULT_MAX_DEPTH,
152 max_parts: DEFAULT_MAX_PARTS,
153 max_encoded_nesting: DEFAULT_MAX_ENCODED_NESTING,
154 kernel: Kernel::best(),
155 }
156 }
157
158 pub fn header(mut self, name: impl Into<HeaderName<'static>>, form: HeaderForm) -> Self {
165 let name = name.into();
166 match (name.resolved_id(), name) {
167 (CONTENT_TYPE | CONTENT_DISPOSITION | CONTENT_TRANSFER_ENCODING, _) => {}
168 (OTHER_ID, HeaderName::Other(name)) if name.is_empty() => {}
169 (OTHER_ID, HeaderName::Other(name)) => {
170 match self
171 .custom
172 .iter_mut()
173 .find(|(custom, _)| custom.eq_ignore_ascii_case(&name))
174 {
175 Some((_, custom_form)) => *custom_form = form,
176 None => self.custom.push((name.into_owned().into_boxed_str(), form)),
177 }
178 }
179 (id, _) => {
180 if let Some(slot) = self.forms.get_mut(usize::from(id)) {
181 *slot = form;
182 if id >= FIRST_VENDOR && !self.configured_vendor.contains(&id) {
183 self.configured_vendor.push(id);
184 }
185 }
186 }
187 }
188 self
189 }
190
191 pub fn unknown_headers(mut self, form: HeaderForm) -> Self {
201 self.unknown = form;
202 let vendor_forms = self.forms.get_mut(FIRST_VENDOR_ID..).unwrap_or_default();
203 for (slot, id) in vendor_forms.iter_mut().zip(FIRST_VENDOR..) {
204 if !self.configured_vendor.contains(&id) {
205 *slot = form;
206 }
207 }
208 self
209 }
210
211 pub fn max_depth(mut self, depth: usize) -> Self {
215 self.max_depth = u32::try_from(depth).unwrap_or(u32::MAX).max(1);
216 self
217 }
218
219 pub fn max_parts(mut self, parts: usize) -> Self {
222 self.max_parts = u32::try_from(parts).unwrap_or(u32::MAX).max(1);
223 self
224 }
225
226 pub fn max_encoded_nesting(mut self, levels: usize) -> Self {
229 self.max_encoded_nesting = u32::try_from(levels).unwrap_or(u32::MAX);
230 self
231 }
232
233 #[cfg(test)]
234 pub(crate) fn kernel(mut self, kernel: Kernel) -> Self {
235 self.kernel = kernel;
236 self
237 }
238
239 pub(crate) fn known_form(&self, id: u16) -> HeaderForm {
240 self.forms.get(id as usize).copied().unwrap_or(self.unknown)
241 }
242
243 pub(crate) fn other_form(&self, name: &[u8]) -> HeaderForm {
244 self.custom
245 .iter()
246 .find(|(custom, _)| custom.as_bytes().eq_ignore_ascii_case(name))
247 .map_or(self.unknown, |(_, form)| *form)
248 }
249
250 pub fn parse<'x>(&self, raw: &'x (impl AsRef<[u8]> + ?Sized)) -> Option<Message<'x>> {
253 let mut message = Message::new(Cow::Borrowed(raw.as_ref()), MessageData::default());
254 self.fill(&mut message, false).then_some(message)
255 }
256
257 pub fn parse_owned(&self, raw: Vec<u8>) -> Option<Message<'static>> {
260 let mut message = Message::new(Cow::Owned(raw), MessageData::default());
261 self.fill(&mut message, false).then_some(message)
262 }
263
264 pub fn parse_headers<'x>(&self, raw: &'x (impl AsRef<[u8]> + ?Sized)) -> Option<Message<'x>> {
273 let mut message = Message::new(Cow::Borrowed(raw.as_ref()), MessageData::default());
274 self.fill(&mut message, true).then_some(message)
275 }
276
277 pub fn parse_with<'x>(
286 &self,
287 raw: &'x (impl AsRef<[u8]> + ?Sized),
288 buffers: &mut MessageBuffers,
289 ) -> Option<Message<'x>> {
290 let mut message = Message::new(
291 Cow::Borrowed(raw.as_ref()),
292 std::mem::take(&mut buffers.data),
293 );
294 message.split_mut().1.clear();
295 self.fill(&mut message, false).then_some(message)
296 }
297
298 fn fill(&self, message: &mut Message<'_>, headers_only: bool) -> bool {
299 let (raw, data) = message.split_mut();
300 u32::try_from(raw.len()).is_ok() && Builder::new(self, data, headers_only).run(raw)
301 }
302
303 pub(crate) fn scan_kernel(&self) -> Kernel {
304 self.kernel
305 }
306
307 pub(crate) fn limits(&self) -> (u32, u32, u32) {
308 (self.max_depth, self.max_parts, self.max_encoded_nesting)
309 }
310}