chiark / gitweb /
multipart: wip ComponentIterator
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 15 Aug 2021 17:51:45 +0000 (18:51 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 15 Aug 2021 17:54:41 +0000 (18:54 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/multipart.rs

index b076458100315b3cf37469a0086b763043def6bd..08570a30829d76d959d0e7e9a8e5fc26f3e0349e 100644 (file)
@@ -80,6 +80,59 @@ pub fn process_boundary<'b>(warnings: &mut Warnings,
   Some(Component { name: part_name.unwrap_or(expected), payload: rhs })
 }
 
+pub struct ComponentIterator<'b> {
+  at_boundary: &'b [u8],
+  boundary_finder: BoundaryFinder,
+}
+
+#[derive(Error,Debug)]
+#[error("missing mime multipart boundary")]
+pub struct MissingBoundary;
+
+impl<'b> ComponentIterator<'b> {
+  #[throws(MissingBoundary)]
+  pub fn resume_mid_component(buf: &'b [u8], boundary_finder: BoundaryFinder)
+                              -> (&'b [u8], Self) {
+    let next_boundary = boundary_finder.find(buf).ok_or(MissingBoundary)?;
+    let part = &buf[0..next_boundary];
+    let part = Self::payload_trim(part);
+    (part, ComponentIterator {
+      at_boundary: &buf[next_boundary..],
+      boundary_finder,
+    })
+  }
+
+  fn payload_trim(payload: &[u8]) -> &[u8] {
+    payload.strip_suffix(b"\r").unwrap_or(payload)
+  }
+
+  #[throws(AE)]
+  pub fn next(&mut self, warnings: &mut Warnings, expected: PartName)
+              -> Option<Component<'b>> {
+    if self.at_boundary.is_empty() { return None }
+
+    let mut comp = match {
+      let boundary_len = self.boundary_finder.needle().len();
+      process_boundary(warnings,
+                       &self.at_boundary[boundary_len..],
+                       expected)?
+    } {
+      None => {
+        self.at_boundary = &self.at_boundary[0..0];
+        return None;
+      },
+      Some(c) => c,
+    };
+
+    let next_boundary = self.boundary_finder.find(&comp.payload)
+      .ok_or(MissingBoundary)?;
+
+    comp.payload = Self::payload_trim(&comp.payload[0..next_boundary]);
+    self.at_boundary = &self.at_boundary[next_boundary..];
+    Some(comp)
+  }
+}
+
 pub struct MetadataFieldIterator<'b> {
   buf: &'b [u8],
   last: Option<usize>,