r#"first multipart component must be name="m""#
)) }
- let nl = memchr::memchr2(b'\r', b'\n', comp.payload_start)
- .ok_or_else(|| anyhow!("no newline in first metadata line?"))?;
+ let mut meta = MetadataFieldIterator::new(comp.payload_start);
+
+ let client = meta.next()
+ .map(|r| r.map_err(Into::into))
+ .unwrap_or_else(|| Err(anyhow!("missing")))
+ .context("client addr")?;
- let client = &comp.payload_start[0..nl];
- let client = str::from_utf8(client).context("client addr utf-8")?;
let client: IpAddr = client.parse().context("client address")?;
// let client = all_clients.get(&client).ok_or_else(|| anyhow!(BAD_CLIENT))?;
Some(Component { name: part_name.unwrap_or(expected), payload_start: rhs })
}
+
+pub struct MetadataFieldIterator<'b> {
+ buf: &'b [u8],
+ last: Option<usize>,
+ iter: memchr::Memchr<'b>,
+}
+
+impl<'b> MetadataFieldIterator<'b> {
+ pub fn new(buf: &'b [u8]) -> Self { Self {
+ buf,
+ last: Some(0),
+ iter: memchr::Memchr::new(b'\n', buf),
+ } }
+}
+
+impl<'b> Iterator for MetadataFieldIterator<'b> {
+ type Item = Result<&'b str, std::str::Utf8Error>;
+ fn next(&mut self) -> Option<Result<&'b str, std::str::Utf8Error>> {
+ let last = self.last?;
+ let (s, last) = match self.iter.next() {
+ Some(nl) => (&self.buf[last..nl], Some(nl+1)),
+ None => (&self.buf[last..], None),
+ };
+ self.last = last;
+ let s = str::from_utf8(s).map(|s| s.trim());
+ Some(s)
+ }
+}
pub use crate::config::{self, InstanceConfig, u32Ext as _};
pub use crate::ini;
pub use crate::ipif::Ipif;
-pub use crate::multipart::{self, PartName};
+pub use crate::multipart::{self, PartName, MetadataFieldIterator};
pub use crate::utils::*;
pub use crate::queue::*;
pub use crate::reporter::*;