use super::Syntax;
use structured_asn1::memory::{MemoryError, Work};
pub fn media_type_or_headers<W: Work>(value: &[u8], work: &W) -> Result<bool, MemoryError> {
let mut media = Syntax::<false>::new();
if media.feed(value, work)? && media.complete() {
return Ok(true);
}
let cost = u64::try_from(value.len())
.ok()
.and_then(|length| length.checked_mul(4))
.ok_or(MemoryError::WorkExceeded)?;
work.charge_work(cost)?;
let mut at = 0;
let mut content_type = false;
while at < value.len() {
if value[at] == b'\r' && value.get(at + 1) == Some(&b'\n') {
return Ok(content_type && at + 2 == value.len());
}
let start = at;
while at < value.len() && value[at] != b':' {
if !matches!(value[at], 33..=126) {
return Ok(false);
}
at += 1;
}
if at == start || at == value.len() {
return Ok(false);
}
let name = &value[start..at];
at += 1;
let body = at;
while at < value.len() {
if value[at] == b'\r' {
if value.get(at + 1) != Some(&b'\n') {
return Ok(false);
}
if !matches!(value.get(at + 2), Some(b' ' | b'\t')) {
break;
}
at += 2;
} else if value[at] == b'\n' || !value[at].is_ascii() {
return Ok(false);
}
at += 1;
}
if name.eq_ignore_ascii_case(b"Content-Type") {
if content_type {
return Ok(false);
}
let mut media = Syntax::<false>::new();
if !media.feed(&value[body..at], work)? || !media.complete() {
return Ok(false);
}
content_type = true;
}
if at < value.len() {
at += 2;
}
}
Ok(content_type)
}