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}