#[cfg(feature="std")]
use {
alloc::{
string::String,
vec::Vec,
},
core::str::FromStr,
std::{
io::{Error, ErrorKind, Read},
},
crate::{Header, HeaderMap, IoResult, LINE_BREAK},
};
#[cfg(feature="std")]
pub fn read_headers<R>(r: &mut R, line_buffer: &mut [u8], bytes: Option<Vec<u8>>) -> IoResult<(HeaderMap, Option<Vec<u8>>)> where R: Read {
const MAX_SIZE: usize = 1024 * 1024;
let lf = LINE_BREAK.as_bytes().last();
let mut bytes = bytes.unwrap_or_else(|| Vec::with_capacity(1024));
let mut result = HeaderMap::new();
let mut total_read: usize = 0;
loop {
let line = match bytes.iter().position(|b| lf.map(|lf| lf == b).unwrap_or(false)) {
Some(end) => match end.checked_sub(LINE_BREAK.len()).map(|start| match &bytes[start + 1 ..= end] == LINE_BREAK.as_bytes() {
true => Some(end + 1),
false => None,
}) {
Some(Some(idx)) => String::from_utf8(bytes.drain(..idx).collect()).map_err(|_|
Error::new(ErrorKind::InvalidData, __!("Invalid header"))
)?,
_ => return Err(Error::new(ErrorKind::InvalidData, __!("Invalid header"))),
},
None => match r.read(line_buffer)? {
0 => return Err(Error::new(ErrorKind::UnexpectedEof, __!("Invalid headers"))),
read => match total_read.checked_add(read) {
Some(n) if n <= MAX_SIZE => {
total_read = n;
bytes.extend(&line_buffer[..read]);
continue;
},
_ => return Err(Error::new(ErrorKind::InvalidData, __!("Headers too large"))),
},
},
};
let line = line.trim();
if line.is_empty() == false {
let mut parts = line.splitn(2, ':');
match (parts.next(), parts.next(), parts.next()) {
(Some(header), Some(value), None) => drop(result.insert(
Header::from_str(header)?,
value.chars().skip_while(|c| c == &' ').collect(),
)),
_ => return Err(Error::new(ErrorKind::InvalidData, __!("Invalid header: {:?}", line))),
};
}
match bytes.starts_with(LINE_BREAK.as_bytes()) {
true => match result.is_empty() {
true => return Err(Error::new(ErrorKind::InvalidData, __!("Missing headers"))),
false => {
bytes.drain(..LINE_BREAK.len());
return Ok((result, match bytes.is_empty() {
true => None,
false => Some(bytes),
}));
},
},
false => if line.is_empty() {
return Err(Error::new(ErrorKind::InvalidData, __!("Invalid header")));
},
};
}
}