http1_spec/
head_parser.rs

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
17//
18//
19//
20const 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//
29//
30//
31#[derive(Debug, Clone)]
32pub struct HeadParseConfig {
33    header_max_len: usize,
34    headers_max_len: usize,
35    // res
36    reason_phrase_max_len: usize,
37    // req
38    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            // res
47            reason_phrase_max_len: 40,
48            // req
49            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    // res
81    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    // req
89    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//
106//
107//
108#[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    // res
126    TooLongStatusCode,
127    InvalidStatusCode(InvalidStatusCode),
128    TooLongReasonPhrase,
129    // req
130    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
147//
148//
149//
150pub 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        // TODO, valid HEADERS_MAX_LEN
185
186        //
187        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    //
211    // res
212    //
213    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    //
300    // req
301    //
302    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}