use std::io::{self, BufRead};
use crate::bytes::ByteSearch;
use crate::error::{Error, ParseErrorKind, ReadError};
use super::{DEFAULT_MAX_HEADERS, Request};
#[derive(Debug)]
pub struct ReadRequest<'buf, const MAX_HDRS: usize = DEFAULT_MAX_HEADERS> {
pub(super) request: Request<'buf, MAX_HDRS>,
pub(super) prefetch: &'buf [u8],
pub(super) body_offset: usize,
pub(super) bytes_read: usize,
}
impl<'buf, const MAX_HDRS: usize> ReadRequest<'buf, MAX_HDRS> {
#[inline]
#[must_use]
pub const fn request(&self) -> &Request<'buf, MAX_HDRS> {
&self.request
}
#[inline]
#[must_use]
pub const fn prefetch(&self) -> &'buf [u8] {
self.prefetch
}
#[inline]
#[must_use]
pub const fn body_offset(&self) -> usize {
self.body_offset
}
#[inline]
#[must_use]
pub const fn bytes_read(&self) -> usize {
self.bytes_read
}
pub fn stream_body_to(
&self,
reader: &mut impl io::BufRead,
writer: &mut impl io::Write,
) -> Result<u64, Error> {
self.stream_body_to_limited(reader, writer, crate::body::DEFAULT_MAX_BODY_SIZE)
}
pub fn stream_body_to_limited(
&self,
reader: &mut impl io::BufRead,
writer: &mut impl io::Write,
max_body_size: u64,
) -> Result<u64, Error> {
crate::body::stream_body(
reader,
writer,
self.prefetch,
self.request.body_kind(),
max_body_size,
)
}
pub fn stream_body_to_with<
const CHUNK_LINE_BUF: usize,
const MAX_BODY_SIZE: u64,
const MAX_TRAILER_SIZE: usize,
>(
&self,
reader: &mut impl io::BufRead,
writer: &mut impl io::Write,
) -> Result<u64, Error> {
crate::body::stream_body_with::<CHUNK_LINE_BUF, MAX_BODY_SIZE, MAX_TRAILER_SIZE>(
reader,
writer,
self.prefetch,
self.request.body_kind(),
)
}
pub fn body_reader<R: io::BufRead>(&self, reader: R) -> crate::body::BodyReader<'_, R> {
crate::body::BodyReader::new(
reader,
self.prefetch,
self.request.body_kind(),
crate::body::DEFAULT_MAX_BODY_SIZE,
)
}
}
impl<'buf, const MAX_HDRS: usize> Request<'buf, MAX_HDRS> {
pub fn read(
reader: &mut impl BufRead,
buf: &'buf mut [u8],
) -> Result<ReadRequest<'buf, MAX_HDRS>, ReadError> {
let buf_size = buf.len();
let mut filled = 0;
let header_end = loop {
if filled >= buf_size {
return Err(ReadError {
error: ParseErrorKind::HeadersTooLarge.into(),
bytes_read: filled,
});
}
let available = match reader.fill_buf() {
Ok([]) => {
return Err(ReadError {
error: ParseErrorKind::ConnectionClosed.into(),
bytes_read: filled,
});
}
Ok(b) => b,
Err(e) => {
return Err(ReadError {
error: Error::Io(e),
bytes_read: filled,
});
}
};
let n = available.len().min(buf_size - filled);
buf[filled..filled + n].copy_from_slice(&available[..n]);
reader.consume(n);
filled += n;
let search_start = filled.saturating_sub(n + 3);
if let Some(pos) = buf[..filled].find_header_end(search_start) {
break pos;
}
};
let request = Self::parse_impl(&buf[..header_end]).map_err(|error| ReadError {
error: error.into(),
bytes_read: filled,
})?;
Ok(ReadRequest {
request,
prefetch: &buf[header_end..filled],
body_offset: header_end,
bytes_read: filled,
})
}
}