Skip to main content

wreq_proto/proto/
http1.rs

1//! HTTP/1 protocol implementation and utilities.
2
3mod buf;
4mod decode;
5mod encode;
6mod io;
7
8pub(crate) mod conn;
9pub(crate) mod dispatch;
10pub(crate) mod role;
11
12use bytes::BytesMut;
13use http::{HeaderMap, Method};
14use httparse::ParserConfig;
15
16use self::{conn::Conn, decode::Decoder, encode::Encoder, io::MINIMUM_MAX_BUFFER_SIZE};
17use super::{BodyLength, MessageHead};
18use crate::{
19    body::DecodedLength,
20    error::{Error, Parse, Result},
21    ext::OnInformational,
22};
23
24pub(crate) trait Http1Transaction {
25    type Incoming;
26
27    type Outgoing: Default;
28
29    #[cfg(feature = "tracing")]
30    const LOG: &'static str;
31
32    fn parse(
33        bytes: &mut BytesMut,
34        ctx: ParseContext<'_>,
35    ) -> Result<Option<ParsedMessage<Self::Incoming>>, Parse>;
36
37    fn encode(enc: Encode<'_, Self::Outgoing>, dst: &mut Vec<u8>) -> Result<Encoder>;
38
39    fn on_error(err: &Error) -> Option<MessageHead<Self::Outgoing>>;
40
41    fn update_date() {}
42}
43
44#[derive(Debug)]
45pub(crate) struct ParsedMessage<T> {
46    head: MessageHead<T>,
47    decode: DecodedLength,
48    expect_continue: bool,
49    keep_alive: bool,
50    wants_upgrade: bool,
51}
52
53pub(crate) struct ParseContext<'a> {
54    cached_headers: &'a mut Option<HeaderMap>,
55    req_method: &'a mut Option<Method>,
56    h1_parser_config: &'a ParserConfig,
57    h1_max_headers: Option<usize>,
58    h09_responses: bool,
59    on_informational: &'a mut Option<OnInformational>,
60}
61
62/// Passed to Http1Transaction::encode
63pub(crate) struct Encode<'a, T> {
64    head: &'a mut MessageHead<T>,
65    body: Option<BodyLength>,
66    req_method: &'a mut Option<Method>,
67}
68
69/// Extra flags that a request "wants", like expect-continue or upgrades.
70#[derive(Clone, Copy, Debug)]
71struct Wants(u8);
72
73impl Wants {
74    const EMPTY: Wants = Wants(0b00);
75    const EXPECT: Wants = Wants(0b01);
76    const UPGRADE: Wants = Wants(0b10);
77
78    #[inline]
79    #[must_use]
80    fn add(self, other: Wants) -> Wants {
81        Wants(self.0 | other.0)
82    }
83
84    #[inline]
85    fn contains(&self, other: Wants) -> bool {
86        (self.0 & other.0) == other.0
87    }
88}
89
90/// Builder for `Http1Options`.
91#[must_use]
92#[derive(Debug)]
93pub struct Http1OptionsBuilder {
94    opts: Http1Options,
95}
96
97/// Options for tweaking HTTP/1 connection behavior.
98///
99/// Use `Http1Options` to adjust how HTTP/1 connections work—things like allowing HTTP/0.9
100/// responses, controlling header handling, buffer sizes, and more. Most settings are optional and
101/// have reasonable defaults.
102#[non_exhaustive]
103#[derive(Debug, Default, Clone)]
104pub struct Http1Options {
105    /// Enable support for HTTP/0.9 responses.
106    pub h09_responses: bool,
107
108    /// Whether to use vectored writes for HTTP/1 connections.
109    pub h1_writev: Option<bool>,
110
111    /// Maximum number of headers allowed in HTTP/1 responses.
112    pub h1_max_headers: Option<usize>,
113
114    /// Exact size of the read buffer to use for HTTP/1 connections.
115    pub h1_read_buf_exact_size: Option<usize>,
116
117    /// Maximum buffer size for HTTP/1 connections.
118    pub h1_max_buf_size: Option<usize>,
119
120    /// Whether to ignore invalid headers in HTTP/1 responses.
121    pub ignore_invalid_headers_in_responses: bool,
122
123    /// Whether to allow spaces after header names in HTTP/1 responses.
124    pub allow_spaces_after_header_name_in_responses: bool,
125
126    /// Whether to allow obsolete multiline headers in HTTP/1 responses.
127    pub allow_obsolete_multiline_headers_in_responses: bool,
128}
129
130impl Http1OptionsBuilder {
131    /// Set the `http09_responses` field.
132    #[inline]
133    pub fn http09_responses(mut self, enabled: bool) -> Self {
134        self.opts.h09_responses = enabled;
135        self
136    }
137
138    /// Set whether HTTP/1 connections should try to use vectored writes,
139    /// or always flatten into a single buffer.
140    ///
141    /// Note that setting this to false may mean more copies of body data,
142    /// but may also improve performance when an IO transport doesn't
143    /// support vectored writes well, such as most TLS implementations.
144    ///
145    /// Setting this to true will force crate::core: to use queued strategy
146    /// which may eliminate unnecessary cloning on some TLS backends
147    ///
148    /// Default is `auto`. In this mode crate::core: will try to guess which
149    /// mode to use
150    #[inline]
151    pub fn writev(mut self, writev: Option<bool>) -> Self {
152        self.opts.h1_writev = writev;
153        self
154    }
155
156    /// Set the maximum number of headers.
157    ///
158    /// When a response is received, the parser will reserve a buffer to store headers for optimal
159    /// performance.
160    ///
161    /// If client receives more headers than the buffer size, the error "message header too large"
162    /// is returned.
163    ///
164    /// Note that headers is allocated on the stack by default, which has higher performance. After
165    /// setting this value, headers will be allocated in heap memory, that is, heap memory
166    /// allocation will occur for each response, and there will be a performance drop of about 5%.
167    ///
168    /// Default is 100.
169    #[inline]
170    pub fn max_headers(mut self, max_headers: usize) -> Self {
171        self.opts.h1_max_headers = Some(max_headers);
172        self
173    }
174
175    /// Sets the exact size of the read buffer to *always* use.
176    ///
177    /// Note that setting this option unsets the `max_buf_size` option.
178    ///
179    /// Default is an adaptive read buffer.
180    #[inline]
181    pub fn read_buf_exact_size(mut self, sz: Option<usize>) -> Self {
182        self.opts.h1_read_buf_exact_size = sz;
183        self.opts.h1_max_buf_size = None;
184        self
185    }
186
187    /// Set the maximum buffer size for the connection.
188    ///
189    /// Default is ~400kb.
190    ///
191    /// Note that setting this option unsets the `read_exact_buf_size` option.
192    ///
193    /// # Panics
194    ///
195    /// The minimum value allowed is 8192. This method panics if the passed `max` is less than the
196    /// minimum.
197    #[inline]
198    pub fn max_buf_size(mut self, max: usize) -> Self {
199        assert!(
200            max >= MINIMUM_MAX_BUFFER_SIZE,
201            "the max_buf_size cannot be smaller than the minimum that h1 specifies."
202        );
203
204        self.opts.h1_max_buf_size = Some(max);
205        self.opts.h1_read_buf_exact_size = None;
206        self
207    }
208
209    /// Set whether HTTP/1 connections will accept spaces between header names
210    /// and the colon that follow them in responses.
211    ///
212    /// You probably don't need this, here is what [RFC 7230 Section 3.2.4.] has
213    /// to say about it:
214    ///
215    /// > No whitespace is allowed between the header field-name and colon. In
216    /// > the past, differences in the handling of such whitespace have led to
217    /// > security vulnerabilities in request routing and response handling. A
218    /// > server MUST reject any received request message that contains
219    /// > whitespace between a header field-name and colon with a response code
220    /// > of 400 (Bad Request). A proxy MUST remove any such whitespace from a
221    /// > response message before forwarding the message downstream.
222    ///
223    /// Default is false.
224    ///
225    /// [RFC 7230 Section 3.2.4.]: https://tools.ietf.org/html/rfc7230#section-3.2.4
226    #[inline]
227    pub fn allow_spaces_after_header_name_in_responses(mut self, enabled: bool) -> Self {
228        self.opts.allow_spaces_after_header_name_in_responses = enabled;
229        self
230    }
231
232    /// Set whether HTTP/1 connections will silently ignored malformed header lines.
233    ///
234    /// If this is enabled and a header line does not start with a valid header
235    /// name, or does not include a colon at all, the line will be silently ignored
236    /// and no error will be reported.
237    ///
238    /// Default is false.
239    #[inline]
240    pub fn ignore_invalid_headers_in_responses(mut self, enabled: bool) -> Self {
241        self.opts.ignore_invalid_headers_in_responses = enabled;
242        self
243    }
244
245    /// Set the `allow_obsolete_multiline_headers_in_responses` field.
246    #[inline]
247    pub fn allow_obsolete_multiline_headers_in_responses(mut self, value: bool) -> Self {
248        self.opts.allow_obsolete_multiline_headers_in_responses = value;
249        self
250    }
251
252    /// Build the [`Http1Options`] instance.
253    #[inline]
254    pub fn build(self) -> Http1Options {
255        self.opts
256    }
257}
258
259impl Http1Options {
260    /// Create a new [`Http1OptionsBuilder`].
261    pub fn builder() -> Http1OptionsBuilder {
262        Http1OptionsBuilder {
263            opts: Http1Options::default(),
264        }
265    }
266}