http1_spec/
response_head_parser.rs

1use std::io::{BufRead, Read as _};
2
3use http::{
4    response::Parts as ResponseParts, HeaderMap, HeaderValue, Response, StatusCode, Version,
5};
6
7use crate::{
8    head_parser::{HeadParseConfig, HeadParseError, HeadParseOutput, HeadParser},
9    ReasonPhrase,
10};
11
12//
13//
14//
15#[derive(Default)]
16pub struct ResponseHeadParser {
17    pub http_version: Version,
18    pub status_code: StatusCode,
19    pub reason_phrase: ReasonPhrase,
20    pub headers: HeaderMap<HeaderValue>,
21    //
22    config: HeadParseConfig,
23    //
24    state: State,
25    buf: Vec<u8>,
26}
27
28#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
29enum State {
30    Idle,
31    HttpVersionParsed,
32    StatusCodeParsed,
33    ReasonPhraseParsed,
34    HeadersParsing,
35}
36impl Default for State {
37    fn default() -> Self {
38        Self::Idle
39    }
40}
41
42impl ResponseHeadParser {
43    pub fn to_response_parts(&self) -> ResponseParts {
44        let (mut parts, _) = Response::new(()).into_parts();
45        parts.status = self.status_code;
46        parts.version = self.http_version;
47        parts.headers = self.headers.to_owned();
48        parts.extensions.insert(self.reason_phrase.to_owned());
49        parts
50    }
51
52    pub fn to_response<B>(&self, body: B) -> Response<B> {
53        let parts = self.to_response_parts();
54        Response::from_parts(parts, body)
55    }
56}
57
58//
59//
60//
61impl HeadParser for ResponseHeadParser {
62    fn new() -> Self {
63        Self::default()
64    }
65    fn with_config(config: HeadParseConfig) -> Self {
66        let buf = Vec::with_capacity(config.buf_capacity());
67        let headers = HeaderMap::with_capacity(config.header_map_capacity());
68        ResponseHeadParser {
69            config,
70            buf,
71            headers,
72            ..Default::default()
73        }
74    }
75
76    fn get_headers(&self) -> &HeaderMap<HeaderValue> {
77        &self.headers
78    }
79    fn get_version(&self) -> &Version {
80        &self.http_version
81    }
82
83    fn parse<R: BufRead>(&mut self, r: &mut R) -> Result<HeadParseOutput, HeadParseError> {
84        let mut take = r.take(0);
85        let mut parsed_num_bytes = 0_usize;
86
87        if self.state < State::HttpVersionParsed {
88            // http_version
89            self.buf.clear();
90            match Self::parse_http_version_for_response(&mut take, &mut self.buf)? {
91                Some((http_version, n)) => {
92                    self.state = State::HttpVersionParsed;
93
94                    self.http_version = http_version;
95                    parsed_num_bytes += n;
96                }
97                None => return Ok(HeadParseOutput::Partial(parsed_num_bytes)),
98            }
99        }
100
101        if self.state < State::StatusCodeParsed {
102            // status_code
103            self.buf.clear();
104            match Self::parse_status_code(&mut take, &mut self.buf)? {
105                Some((status_code, n)) => {
106                    self.state = State::StatusCodeParsed;
107
108                    self.status_code = status_code;
109                    parsed_num_bytes += n;
110                }
111                None => return Ok(HeadParseOutput::Partial(parsed_num_bytes)),
112            }
113        }
114
115        if self.state < State::ReasonPhraseParsed {
116            // reason_phrase
117            self.buf.clear();
118            match Self::parse_reason_phrase(&mut take, &mut self.buf, &self.config)? {
119                Some((reason_phrase, n)) => {
120                    self.state = State::ReasonPhraseParsed;
121
122                    self.reason_phrase = reason_phrase;
123                    parsed_num_bytes += n;
124                }
125                None => return Ok(HeadParseOutput::Partial(parsed_num_bytes)),
126            }
127        }
128
129        // headers
130        if self.state < State::HeadersParsing {
131            self.headers.clear();
132        }
133        loop {
134            if self.state <= State::HeadersParsing {
135                self.buf.clear();
136                match Self::parse_header(&mut take, &mut self.buf, &self.config, &mut self.headers)?
137                {
138                    Some((is_all_completed, n)) => {
139                        parsed_num_bytes += n;
140
141                        if is_all_completed {
142                            self.state = State::Idle;
143
144                            return Ok(HeadParseOutput::Completed(parsed_num_bytes));
145                        } else {
146                            self.state = State::HeadersParsing;
147
148                            continue;
149                        }
150                    }
151                    None => return Ok(HeadParseOutput::Partial(parsed_num_bytes)),
152                }
153            } else {
154                unreachable!()
155            }
156        }
157    }
158}
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163
164    #[test]
165    fn test_to_response() {
166        let p = ResponseHeadParser {
167            http_version: Version::HTTP_2,
168            status_code: StatusCode::CREATED,
169            reason_phrase: Some(b"MyCreated".to_vec()),
170            headers: {
171                let mut h = HeaderMap::new();
172                h.insert("x-foo", "bar".parse().unwrap());
173                h
174            },
175            ..Default::default()
176        };
177
178        let res = p.to_response("body");
179        assert_eq!(res.version(), Version::HTTP_2);
180        assert_eq!(res.status(), StatusCode::CREATED);
181        assert_eq!(res.headers().get("x-foo").unwrap(), "bar");
182        assert_eq!(
183            res.extensions().get::<ReasonPhrase>().unwrap(),
184            &Some(b"MyCreated".to_vec())
185        );
186        assert_eq!(res.body(), &"body");
187    }
188}