mod buf;
mod decode;
mod encode;
mod io;
pub(crate) mod conn;
pub(crate) mod dispatch;
pub(crate) mod role;
use bytes::BytesMut;
use http::{HeaderMap, Method};
use httparse::ParserConfig;
use self::{conn::Conn, decode::Decoder, encode::Encoder, io::MINIMUM_MAX_BUFFER_SIZE};
use super::{BodyLength, MessageHead};
use crate::{
body::DecodedLength,
error::{Error, Parse, Result},
ext::OnInformational,
};
pub(crate) trait Http1Transaction {
type Incoming;
type Outgoing: Default;
#[cfg(feature = "tracing")]
const LOG: &'static str;
fn parse(
bytes: &mut BytesMut,
ctx: ParseContext<'_>,
) -> Result<Option<ParsedMessage<Self::Incoming>>, Parse>;
fn encode(enc: Encode<'_, Self::Outgoing>, dst: &mut Vec<u8>) -> Result<Encoder>;
fn on_error(err: &Error) -> Option<MessageHead<Self::Outgoing>>;
fn update_date() {}
}
#[derive(Debug)]
pub(crate) struct ParsedMessage<T> {
head: MessageHead<T>,
decode: DecodedLength,
expect_continue: bool,
keep_alive: bool,
wants_upgrade: bool,
}
pub(crate) struct ParseContext<'a> {
cached_headers: &'a mut Option<HeaderMap>,
req_method: &'a mut Option<Method>,
h1_parser_config: &'a ParserConfig,
h1_max_headers: Option<usize>,
h09_responses: bool,
on_informational: &'a mut Option<OnInformational>,
}
pub(crate) struct Encode<'a, T> {
head: &'a mut MessageHead<T>,
body: Option<BodyLength>,
req_method: &'a mut Option<Method>,
}
#[derive(Clone, Copy, Debug)]
struct Wants(u8);
impl Wants {
const EMPTY: Wants = Wants(0b00);
const EXPECT: Wants = Wants(0b01);
const UPGRADE: Wants = Wants(0b10);
#[inline]
#[must_use]
fn add(self, other: Wants) -> Wants {
Wants(self.0 | other.0)
}
#[inline]
fn contains(&self, other: Wants) -> bool {
(self.0 & other.0) == other.0
}
}
#[must_use]
#[derive(Debug)]
pub struct Http1OptionsBuilder {
opts: Http1Options,
}
#[non_exhaustive]
#[derive(Debug, Default, Clone)]
pub struct Http1Options {
pub h09_responses: bool,
pub h1_writev: Option<bool>,
pub h1_max_headers: Option<usize>,
pub h1_read_buf_exact_size: Option<usize>,
pub h1_max_buf_size: Option<usize>,
pub ignore_invalid_headers_in_responses: bool,
pub allow_spaces_after_header_name_in_responses: bool,
pub allow_obsolete_multiline_headers_in_responses: bool,
}
impl Http1OptionsBuilder {
#[inline]
pub fn http09_responses(mut self, enabled: bool) -> Self {
self.opts.h09_responses = enabled;
self
}
#[inline]
pub fn writev(mut self, writev: Option<bool>) -> Self {
self.opts.h1_writev = writev;
self
}
#[inline]
pub fn max_headers(mut self, max_headers: usize) -> Self {
self.opts.h1_max_headers = Some(max_headers);
self
}
#[inline]
pub fn read_buf_exact_size(mut self, sz: Option<usize>) -> Self {
self.opts.h1_read_buf_exact_size = sz;
self.opts.h1_max_buf_size = None;
self
}
#[inline]
pub fn max_buf_size(mut self, max: usize) -> Self {
assert!(
max >= MINIMUM_MAX_BUFFER_SIZE,
"the max_buf_size cannot be smaller than the minimum that h1 specifies."
);
self.opts.h1_max_buf_size = Some(max);
self.opts.h1_read_buf_exact_size = None;
self
}
#[inline]
pub fn allow_spaces_after_header_name_in_responses(mut self, enabled: bool) -> Self {
self.opts.allow_spaces_after_header_name_in_responses = enabled;
self
}
#[inline]
pub fn ignore_invalid_headers_in_responses(mut self, enabled: bool) -> Self {
self.opts.ignore_invalid_headers_in_responses = enabled;
self
}
#[inline]
pub fn allow_obsolete_multiline_headers_in_responses(mut self, value: bool) -> Self {
self.opts.allow_obsolete_multiline_headers_in_responses = value;
self
}
#[inline]
pub fn build(self) -> Http1Options {
self.opts
}
}
impl Http1Options {
pub fn builder() -> Http1OptionsBuilder {
Http1OptionsBuilder {
opts: Http1Options::default(),
}
}
}