http_protocol/parse/
mod.rs

1use crate::header::{check_header_value, get_header};
2use crate::http_version::get_http_version;
3use crate::method::parse_method;
4// use crate::parse::ParsePosition::Headers;
5use crate::request::{RequestBuilder, RequestError};
6use crate::{Headers, Method, RequestUri};
7use std::error::Error;
8
9#[derive(Debug, PartialEq)]
10pub enum ParsePosition {
11    RequestLine,
12    Headers,
13    Body,
14    RequestEnd,
15}
16
17#[inline]
18fn parse_request_line(
19    current_position: &mut ParsePosition,
20    stop_position: &mut ParsePosition,
21    buffer: &mut Vec<u8>,
22    index: &mut usize,
23) -> Result<RequestBuilder, Box<dyn Error>> {
24    // meta[0] - sp1
25    // meta[1] - sp2
26    // meta[2] - request line end
27    let mut meta = [0usize; 3];
28    let mut meta_count = 0;
29
30    for i in *index..buffer.len() {
31        if buffer[i] == sp!() {
32            meta[meta_count % 2] = i;
33            meta_count += 1;
34            if meta_count > 2 {
35                return Err(RequestError::InvalidRequestLine.into());
36            }
37            continue;
38        }
39        if buffer[i] == lf!() {
40            if (i - *index) < 14 {
41                return Err(RequestError::InvalidRequestLine.into());
42            }
43            if buffer[i - 1] == cr!() {
44                meta[2] = i - 2;
45                break;
46            }
47            return Err(RequestError::InvalidRequestLine.into());
48        }
49    }
50
51    if meta[2] == 0 {
52        return Ok(RequestBuilder::empty());
53    }
54
55    if !(meta[0] > *index && meta[1] > meta[0] && meta[2] > meta[1]) {
56        return Err(RequestError::InvalidRequestLine.into());
57    }
58
59    let method = parse_method(&buffer[*index..meta[0]])?;
60    let http_version = get_http_version(&buffer[(meta[1] + 1)..=meta[2]])?;
61    let request_uri = RequestUri::new(buffer[(meta[0] + 1)..meta[1]].to_owned());
62
63    *current_position = ParsePosition::Headers;
64
65    *stop_position = match method {
66        Method::Get => ParsePosition::Body,
67        Method::Post => ParsePosition::RequestEnd,
68        _ => ParsePosition::Body,
69    };
70
71    *index += meta[2] + 3;
72
73    Ok(RequestBuilder {
74        method: Some(method),
75        request_uri: Some(request_uri),
76        http_version: Some(http_version),
77        headers: None,
78        body: None,
79    })
80}
81
82#[test]
83fn parse_request_line_0() {
84    let reference = RequestBuilder {
85        method: Some(Method::Get),
86        request_uri: Some(RequestUri::new(b"/path".to_vec())),
87        http_version: Some(HttpVersion::Http11),
88        headers: None,
89        body: None,
90    };
91
92    let mut current_position = ParsePosition::RequestLine;
93    let mut stop_position = ParsePosition::RequestEnd;
94    let mut index = 0usize;
95    let mut buffer = b"GET /path HTTP/1.1\r\n".to_vec();
96    let request_part = parse_request_line(
97        &mut current_position,
98        &mut stop_position,
99        &mut buffer,
100        &mut index,
101    )
102    .unwrap();
103    assert_eq!(request_part, reference);
104}
105
106#[inline]
107fn check_min_header_length(s_idx: usize, e_idx: usize) -> Result<(), Box<dyn Error>> {
108    if e_idx - s_idx < 5 {
109        return Err(RequestError::InvalidHeader.into());
110    }
111    Ok(())
112}
113
114fn parse_headers(
115    current_position: &mut ParsePosition,
116    buffer: &mut Vec<u8>,
117    index: &mut usize,
118) -> Result<RequestBuilder, Box<dyn Error>> {
119    let mut index_pairs = Vec::<(usize, usize)>::new();
120
121    let mut s_idx = *index;
122    let mut e_idx = *index;
123
124    for i in *index..buffer.len() {
125        if buffer[i] == lf!() {
126            if buffer[i - 1] != cr!() {
127                return Err(RequestError::InvalidHeader.into());
128            }
129            if buffer[i - 2] == lf!() {
130                break;
131            }
132            e_idx = i - 2;
133            check_min_header_length(s_idx, e_idx)?;
134            index_pairs.push((s_idx, e_idx));
135            s_idx = i + 1;
136            e_idx = i + 1;
137        }
138    }
139
140    println!("{:?}", index_pairs);
141
142    let mut headers = Headers::new();
143
144    for (s_idx, e_idx) in index_pairs {
145        let header = &buffer[s_idx..=e_idx];
146
147        let mut m = 0;
148        for i in 0..header.len() {
149            if header[i] == (':' as u8) {
150                m = i - 1;
151                break;
152            }
153        }
154
155        let header_name = &header[0..=m];
156        let header_value = &header[m + 3..];
157        let header_enum = get_header(header_name)?;
158        check_header_value(header_value)?;
159        headers.insert(header_enum, header_value.to_vec());
160    }
161
162    if *index - e_idx > 0 && buffer[e_idx] == lf!() && buffer[e_idx + 1] == cr!() {
163        *current_position = ParsePosition::Body;
164        *index = e_idx + 2;
165    }
166
167    Ok(RequestBuilder {
168        method: None,
169        request_uri: None,
170        http_version: None,
171        headers: Some(headers),
172        body: None,
173    })
174}
175
176pub fn parse_request(
177    current_position: &mut ParsePosition,
178    stop_position: &mut ParsePosition,
179    buffer: &mut Vec<u8>,
180) -> Result<RequestBuilder, Box<dyn Error>> {
181    let mut index = 0;
182
183    let mut request_part = RequestBuilder::empty();
184
185    if *current_position == ParsePosition::RequestLine {
186        request_part =
187            request_part + parse_request_line(current_position, stop_position, buffer, &mut index)?;
188    }
189
190    if *current_position == ParsePosition::Headers {
191        request_part = request_part + parse_headers(current_position, buffer, &mut index)?;
192    }
193
194    *buffer = buffer.split_off(index);
195
196    Ok(request_part)
197}