http_protocol/parse/
mod.rs1use crate::header::{check_header_value, get_header};
2use crate::http_version::get_http_version;
3use crate::method::parse_method;
4use 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 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}