1use core::cmp::min;
2use std::io::{BufRead, Error as IoError, ErrorKind as IoErrorKind, Take};
3
4use http::{
5 header::{HeaderName, InvalidHeaderName, InvalidHeaderValue},
6 method::InvalidMethod,
7 status::InvalidStatusCode,
8 uri::InvalidUri,
9 HeaderMap, HeaderValue, Method, StatusCode, Uri, Version,
10};
11
12use crate::{
13 ReasonPhrase, COLON, CR, HTTP_VERSION_10, HTTP_VERSION_11, HTTP_VERSION_2, HTTP_VERSION_20,
14 HTTP_VERSION_3, HTTP_VERSION_30, LF, SP,
15};
16
17const HTTP_VERSION_LEN: usize = 8;
21const STATUS_CODE_LEN: usize = 3;
22
23const HEADERS_MAX_LEN: usize = 8192;
24const URI_MAX_LEN: usize = 2048;
25
26pub type IsAllCompleted = bool;
27
28#[derive(Debug, Clone)]
32pub struct HeadParseConfig {
33 header_max_len: usize,
34 headers_max_len: usize,
35 reason_phrase_max_len: usize,
37 method_max_len: usize,
39 uri_max_len: usize,
40}
41impl Default for HeadParseConfig {
42 fn default() -> Self {
43 HeadParseConfig {
44 header_max_len: 32 + 448,
45 headers_max_len: 4096,
46 reason_phrase_max_len: 40,
48 method_max_len: 8,
50 uri_max_len: 512,
51 }
52 }
53}
54impl HeadParseConfig {
55 pub fn new() -> Self {
56 Default::default()
57 }
58
59 pub fn buf_capacity(&self) -> usize {
60 self.get_header_max_len()
61 }
62 pub fn header_map_capacity(&self) -> usize {
63 min(self.get_header_max_len() * 6, self.get_headers_max_len())
64 }
65
66 pub fn set_header_max_len(&mut self, value: u16) -> &mut Self {
67 self.header_max_len = value as usize;
68 self
69 }
70 pub fn get_header_max_len(&self) -> usize {
71 self.header_max_len
72 }
73 pub fn set_headers_max_len(&mut self, value: u16) -> &mut Self {
74 self.headers_max_len = min(value, HEADERS_MAX_LEN as u16) as usize;
75 self
76 }
77 pub fn get_headers_max_len(&self) -> usize {
78 self.headers_max_len
79 }
80 pub fn set_reason_phrase_max_len(&mut self, value: u8) -> &mut Self {
82 self.reason_phrase_max_len = value as usize;
83 self
84 }
85 pub fn get_reason_phrase_max_len(&self) -> usize {
86 self.reason_phrase_max_len
87 }
88 pub fn set_method_max_len(&mut self, value: u8) -> &mut Self {
90 self.method_max_len = value as usize;
91 self
92 }
93 pub fn get_method_max_len(&self) -> usize {
94 self.method_max_len
95 }
96 pub fn set_uri_max_len(&mut self, value: u16) -> &mut Self {
97 self.uri_max_len = min(value, URI_MAX_LEN as u16) as usize;
98 self
99 }
100 pub fn get_uri_max_len(&self) -> usize {
101 self.uri_max_len
102 }
103}
104
105#[derive(Debug, PartialEq, Eq)]
109pub enum HeadParseOutput {
110 Completed(usize),
111 Partial(usize),
112}
113
114#[derive(Debug)]
115pub enum HeadParseError {
116 ReadError(IoError),
117 TooLongHttpVersion,
118 InvalidHttpVersion,
119 TooLongHeader,
120 InvalidHeader,
121 InvalidHeaderName(InvalidHeaderName),
122 InvalidHeaderValue(InvalidHeaderValue),
123 TooLongHeaders,
124 InvalidCRLF,
125 TooLongStatusCode,
127 InvalidStatusCode(InvalidStatusCode),
128 TooLongReasonPhrase,
129 TooLongMethod,
131 InvalidMethod(InvalidMethod),
132 TooLongUri,
133 InvalidUri(InvalidUri),
134}
135impl core::fmt::Display for HeadParseError {
136 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
137 write!(f, "{self:?}")
138 }
139}
140impl std::error::Error for HeadParseError {}
141impl From<HeadParseError> for IoError {
142 fn from(err: HeadParseError) -> IoError {
143 IoError::new(IoErrorKind::InvalidInput, err.to_string())
144 }
145}
146
147pub trait HeadParser {
151 fn new() -> Self;
152 fn with_config(config: HeadParseConfig) -> Self;
153
154 fn get_headers(&self) -> &HeaderMap<HeaderValue>;
155 fn get_version(&self) -> &Version;
156
157 fn parse<R: BufRead>(&mut self, r: &mut R) -> Result<HeadParseOutput, HeadParseError>;
158
159 fn parse_header<R: BufRead>(
160 take: &mut Take<R>,
161 buf: &mut Vec<u8>,
162 config: &HeadParseConfig,
163 headers: &mut HeaderMap<HeaderValue>,
164 ) -> Result<Option<(IsAllCompleted, usize)>, HeadParseError> {
165 let end_bytes_len = 2_usize;
166 take.set_limit(config.get_header_max_len() as u64 + end_bytes_len as u64);
167 let n = take
168 .read_until(LF, buf)
169 .map_err(HeadParseError::ReadError)?;
170 if n < end_bytes_len {
171 return Ok(None);
172 }
173 if !buf[..n].ends_with(&[LF]) {
174 if n >= config.get_header_max_len() {
175 return Err(HeadParseError::TooLongHeader);
176 } else {
177 return Ok(None);
178 }
179 }
180 if !buf[..n - 1].ends_with(&[CR]) {
181 return Err(HeadParseError::InvalidCRLF);
182 }
183
184 if buf[..n - end_bytes_len].is_empty() {
188 return Ok(Some((true, n)));
189 }
190 let header_colon_index = buf[..n - end_bytes_len]
191 .iter()
192 .position(|x| x == &COLON)
193 .ok_or(HeadParseError::InvalidHeader)?;
194 let header_name = &buf[..header_colon_index];
195 let header_value = &buf[header_colon_index + 1..n - end_bytes_len];
196 let mut n_left_whitespace = 0_usize;
197 if header_value[0] == SP {
198 n_left_whitespace += 1;
199 }
200
201 let header_name =
202 HeaderName::from_bytes(header_name).map_err(HeadParseError::InvalidHeaderName)?;
203 let header_value = HeaderValue::from_bytes(&header_value[n_left_whitespace..])
204 .map_err(HeadParseError::InvalidHeaderValue)?;
205
206 headers.insert(header_name, header_value);
207 Ok(Some((false, n)))
208 }
209
210 fn parse_http_version_for_response<R: BufRead>(
214 take: &mut Take<R>,
215 buf: &mut Vec<u8>,
216 ) -> Result<Option<(Version, usize)>, HeadParseError> {
217 let end_bytes_len = 1_usize;
218 take.set_limit(HTTP_VERSION_LEN as u64 + end_bytes_len as u64);
219 let n = take
220 .read_until(SP, buf)
221 .map_err(HeadParseError::ReadError)?;
222 if n < end_bytes_len {
223 return Ok(None);
224 }
225 if !buf[..n].ends_with(&[SP]) {
226 if n >= HTTP_VERSION_LEN {
227 return Err(HeadParseError::TooLongHttpVersion);
228 } else {
229 return Ok(None);
230 }
231 }
232 let http_version = match &buf[..n - end_bytes_len] {
233 HTTP_VERSION_10 => Version::HTTP_10,
234 HTTP_VERSION_11 => Version::HTTP_11,
235 HTTP_VERSION_20 | HTTP_VERSION_2 => Version::HTTP_2,
236 HTTP_VERSION_30 | HTTP_VERSION_3 => Version::HTTP_3,
237 _ => return Err(HeadParseError::InvalidHttpVersion),
238 };
239 Ok(Some((http_version, n)))
240 }
241
242 fn parse_status_code<R: BufRead>(
243 take: &mut Take<R>,
244 buf: &mut Vec<u8>,
245 ) -> Result<Option<(StatusCode, usize)>, HeadParseError> {
246 let end_bytes_len = 1_usize;
247 take.set_limit(STATUS_CODE_LEN as u64 + end_bytes_len as u64);
248 let n = take
249 .read_until(SP, buf)
250 .map_err(HeadParseError::ReadError)?;
251 if n < end_bytes_len {
252 return Ok(None);
253 }
254 if !buf[..n].ends_with(&[SP]) {
255 if n >= STATUS_CODE_LEN {
256 return Err(HeadParseError::TooLongStatusCode);
257 } else {
258 return Ok(None);
259 }
260 }
261 let status_code = StatusCode::from_bytes(&buf[..n - end_bytes_len])
262 .map_err(HeadParseError::InvalidStatusCode)?;
263
264 Ok(Some((status_code, n)))
265 }
266
267 fn parse_reason_phrase<R: BufRead>(
268 take: &mut Take<R>,
269 buf: &mut Vec<u8>,
270 config: &HeadParseConfig,
271 ) -> Result<Option<(ReasonPhrase, usize)>, HeadParseError> {
272 let end_bytes_len = 2_usize;
273 take.set_limit(config.get_reason_phrase_max_len() as u64 + end_bytes_len as u64);
274 let n = take
275 .read_until(LF, buf)
276 .map_err(HeadParseError::ReadError)?;
277 if n < end_bytes_len {
278 return Ok(None);
279 }
280 if !buf[..n].ends_with(&[LF]) {
281 if n >= config.get_reason_phrase_max_len() {
282 return Err(HeadParseError::TooLongReasonPhrase);
283 } else {
284 return Ok(None);
285 }
286 }
287 if !buf[..n - 1].ends_with(&[CR]) {
288 return Err(HeadParseError::InvalidCRLF);
289 }
290 let reason_phrase: ReasonPhrase = if buf[..n - end_bytes_len].is_empty() {
291 None
292 } else {
293 Some(buf[..n - end_bytes_len].to_vec())
294 };
295
296 Ok(Some((reason_phrase, n)))
297 }
298
299 fn parse_method<R: BufRead>(
303 take: &mut Take<R>,
304 buf: &mut Vec<u8>,
305 config: &HeadParseConfig,
306 ) -> Result<Option<(Method, usize)>, HeadParseError> {
307 let end_bytes_len = 1_usize;
308 take.set_limit(config.get_method_max_len() as u64 + end_bytes_len as u64);
309 let n = take
310 .read_until(SP, buf)
311 .map_err(HeadParseError::ReadError)?;
312 if n < end_bytes_len {
313 return Ok(None);
314 }
315 if !buf[..n].ends_with(&[SP]) {
316 if n >= config.get_method_max_len() {
317 return Err(HeadParseError::TooLongMethod);
318 } else {
319 return Ok(None);
320 }
321 }
322 let method =
323 Method::from_bytes(&buf[..n - end_bytes_len]).map_err(HeadParseError::InvalidMethod)?;
324
325 Ok(Some((method, n)))
326 }
327
328 fn parse_uri<R: BufRead>(
329 take: &mut Take<R>,
330 buf: &mut Vec<u8>,
331 config: &HeadParseConfig,
332 ) -> Result<Option<(Uri, usize)>, HeadParseError> {
333 let end_bytes_len = 1_usize;
334 take.set_limit(config.get_uri_max_len() as u64 + end_bytes_len as u64);
335 let n = take
336 .read_until(SP, buf)
337 .map_err(HeadParseError::ReadError)?;
338 if n < end_bytes_len {
339 return Ok(None);
340 }
341 if !buf[..n].ends_with(&[SP]) {
342 if n >= config.get_uri_max_len() {
343 return Err(HeadParseError::TooLongUri);
344 } else {
345 return Ok(None);
346 }
347 }
348 let uri = (&buf[..n - end_bytes_len])
349 .try_into()
350 .map_err(HeadParseError::InvalidUri)?;
351
352 Ok(Some((uri, n)))
353 }
354
355 fn parse_http_version_for_request<R: BufRead>(
356 take: &mut Take<R>,
357 buf: &mut Vec<u8>,
358 ) -> Result<Option<(Version, usize)>, HeadParseError> {
359 let end_bytes_len = 2_usize;
360 take.set_limit(HTTP_VERSION_LEN as u64 + end_bytes_len as u64);
361 let n = take
362 .read_until(LF, buf)
363 .map_err(HeadParseError::ReadError)?;
364 if n < end_bytes_len {
365 return Ok(None);
366 }
367 if !buf[..n].ends_with(&[LF]) {
368 if n >= HTTP_VERSION_LEN {
369 return Err(HeadParseError::TooLongHttpVersion);
370 } else {
371 return Ok(None);
372 }
373 }
374 if !buf[..n - 1].ends_with(&[CR]) {
375 return Err(HeadParseError::InvalidCRLF);
376 }
377 let http_version = match &buf[..n - end_bytes_len] {
378 HTTP_VERSION_10 => Version::HTTP_10,
379 HTTP_VERSION_11 => Version::HTTP_11,
380 HTTP_VERSION_20 | HTTP_VERSION_2 => Version::HTTP_2,
381 HTTP_VERSION_30 | HTTP_VERSION_3 => Version::HTTP_3,
382 _ => return Err(HeadParseError::InvalidHttpVersion),
383 };
384 Ok(Some((http_version, n)))
385 }
386}
387
388#[cfg(test)]
389mod tests {
390 use super::*;
391
392 use std::io::{BufReader, Cursor, Read as _};
393
394 use crate::request_head_parser::RequestHeadParser;
395
396 #[test]
397 fn parse_header_with_multi_colon() -> Result<(), Box<dyn std::error::Error>> {
398 let mut take = BufReader::new(Cursor::new(b"Foo: Bar:Bar\r\n")).take(0);
399 let mut buf = Vec::new();
400 let mut headers = HeaderMap::new();
401
402 RequestHeadParser::parse_header(
403 &mut take,
404 &mut buf,
405 &HeadParseConfig::default(),
406 &mut headers,
407 )?;
408
409 match headers.get("Foo") {
410 Some(header_value) => {
411 assert_eq!(header_value, "Bar:Bar");
412 }
413 None => panic!(),
414 }
415
416 Ok(())
417 }
418}