1#[cfg(test)]
2mod tests;
3#[cfg(test)]
4mod example;
5
6use std::collections::HashMap;
7use std::io;
8use std::io::{BufRead, Cursor, Read};
9use crate::header::Header;
10use crate::ext::string_ext::StringExt;
11use crate::http::HTTP;
12use crate::symbol::SYMBOL;
13use url_build_parse::parse_url;
14use crate::url::URL;
15
16#[derive(PartialEq, Eq, Clone, Debug)]
17pub struct Request {
18 pub method: String,
19 pub request_uri: String,
20 pub http_version: String,
21 pub headers: Vec<Header>,
22 pub body: Vec<u8>,
23}
24
25#[derive(PartialEq, Eq, Clone, Debug)]
26pub struct Method {
27 pub get: &'static str,
28 pub head: &'static str,
29 pub post: &'static str,
30 pub put: &'static str,
31 pub delete: &'static str,
32 pub connect: &'static str,
33 pub options: &'static str,
34 pub trace: &'static str,
35 pub patch: &'static str,
36}
37
38pub const METHOD: Method = Method {
39 get: "GET",
40 head: "HEAD",
41 post: "POST",
42 put: "PUT",
43 delete: "DELETE",
44 connect: "CONNECT",
45 options: "OPTIONS",
46 trace: "TRACE",
47 patch: "PATCH",
48};
49
50impl Request {
51 pub const _ERROR_UNABLE_TO_PARSE_METHOD_AND_REQUEST_URI_AND_HTTP_VERSION: &'static str = "Unable to parse method, request uri and http version";
52
53 pub fn get_header(&self, name: String) -> Option<&Header> {
54 let header = self.headers.iter().find(|x| x.name.to_lowercase() == name.to_lowercase());
55 header
56 }
57
58 pub fn get_domain(&self) -> Result<Option<String>, String> {
59 let boxed_host = &self.get_header(Header::_HOST.to_string());
60 if boxed_host.is_none() {
61 return Ok(None);
62 }
63
64 let host_header = boxed_host.unwrap();
65 let host = host_header.value.to_string();
66
67 let boxed_host_port = host.split_once(&SYMBOL.colon.to_string());
68 if boxed_host_port.is_none() {
69 return Ok(Some(host))
70 }
71
72 let (domain, _port_str) = boxed_host_port.unwrap();
73
74 Ok(Some(domain.to_string()))
75 }
76
77 pub fn get_port(&self) -> Result<Option<i128>, String> {
78 let boxed_host = &self.get_header(Header::_HOST.to_string());
79 if boxed_host.is_none() {
80 return Ok(None);
81 }
82
83 let host_header = boxed_host.unwrap();
84 let host = host_header.value.to_string();
85
86 let boxed_host_port = host.split_once(&SYMBOL.colon.to_string());
87 if boxed_host_port.is_none() {
88 return Ok(None)
89 }
90
91 let (_domain, port_str) = boxed_host_port.unwrap();
92
93 let boxed_port_i128 = port_str.parse::<i128>();
94 if boxed_port_i128.is_err() {
95 let message = boxed_port_i128.err().unwrap().to_string();
96 return Err(message);
97 }
98
99 let port = boxed_port_i128.unwrap();
100
101 Ok(Some(port))
102 }
103
104 pub fn get_query(&self) -> Result<Option<HashMap<String, String>>, String> {
105 self.get_uri_query()
106 }
107
108 pub fn get_uri_query(&self) -> Result<Option<HashMap<String, String>>, String> {
109 let url_array = ["http://", "localhost/", &self.request_uri];
113 let url = url_array.join(SYMBOL.empty_string);
114
115 let boxed_url_components = URL::parse(&url);
116 if boxed_url_components.is_err() {
117 let message = boxed_url_components.err().unwrap().to_string();
118 return Err(message)
119 }
120 Ok(boxed_url_components.unwrap().query)
121 }
122
123 pub fn get_path(&self) -> Result<String, String> {
124 self.get_uri_path()
125 }
126
127 pub fn get_uri_path(&self) -> Result<String, String> {
128 let url_array = ["http://", "localhost", &self.request_uri];
130 let url = url_array.join(SYMBOL.empty_string);
131
132 let boxed_url_components = parse_url(&url);
133 if boxed_url_components.is_err() {
134 let message = boxed_url_components.err().unwrap().to_string();
135 return Err(message)
136 }
137 Ok(boxed_url_components.unwrap().path)
138 }
139
140 pub fn method_list() -> Vec<String> {
141 let method_get = METHOD.get.to_string();
142 let method_head = METHOD.head.to_string();
143 let method_post = METHOD.post.to_string();
144 let method_put = METHOD.put.to_string();
145 let method_delete = METHOD.delete.to_string();
146 let method_connect = METHOD.connect.to_string();
147 let method_options = METHOD.options.to_string();
148 let method_trace = METHOD.trace.to_string();
149 let method_patch = METHOD.patch.to_string();
150
151 let method_list = vec![
152 method_get,
153 method_head,
154 method_post,
155 method_put,
156 method_delete,
157 method_connect,
158 method_options,
159 method_trace,
160 method_patch,
161 ];
162
163 method_list
164 }
165
166 pub fn generate(&self) -> Vec<u8> {
168 let clone = self.clone();
169 let mut request = Request::_generate_request(clone).as_bytes().to_vec();
170
171 let mut body = self.body.clone();
172 request.append(&mut body);
173
174 request
175 }
176
177 pub fn generate_request(request: Request) -> String {
179 Request::_generate_request(request)
180 }
181
182 pub fn _generate_request(request: Request) -> String {
183 let status = [
184 request.method,
185 request.request_uri,
186 request.http_version,
187 SYMBOL.new_line_carriage_return.to_string()
188 ].join(SYMBOL.whitespace);
189
190 let mut headers = SYMBOL.empty_string.to_string();
191 for header in request.headers {
192 let mut header_string = SYMBOL.empty_string.to_string();
193 header_string.push_str(&header.name);
194 header_string.push_str(Header::NAME_VALUE_SEPARATOR);
195 header_string.push_str(&header.value);
196 header_string.push_str(SYMBOL.new_line_carriage_return);
197 headers.push_str(&header_string);
198 }
199
200 let request = format!(
201 "{}{}{}",
202 status,
203 headers,
204 SYMBOL.new_line_carriage_return
205 );
206
207
208 request
209 }
210
211 pub fn parse(request_vec_u8: &[u8]) -> Result<Request, String> {
212 Request::parse_request(request_vec_u8)
213 }
214
215 pub fn parse_request(request_vec_u8: &[u8]) -> Result<Request, String> {
216 let mut cursor = io::Cursor::new(request_vec_u8);
217
218 let mut request = Request {
219 method: "".to_string(),
220 request_uri: "".to_string(),
221 http_version: "".to_string(),
222 headers: vec![],
223 body: vec![],
224 };
225
226 let content_length: usize = 0;
227 let iteration_number : usize = 0;
228 return match Request::cursor_read(&mut cursor, iteration_number, &mut request, content_length) {
229 Ok(_) => {
230 Ok(request)
231 }
232 Err(error_message) => {
233 Err(error_message)
234 }
235 }
236
237 }
238
239
240 pub fn parse_method_and_request_uri_and_http_version_string(http_version_status_code_reason_phrase: &str) -> Result<(String, String, String), String> {
241 let lowercase_unparsed_method_and_request_uri_and_http_version = http_version_status_code_reason_phrase.trim();
242
243 let boxed_split_without_method = lowercase_unparsed_method_and_request_uri_and_http_version.split_once(SYMBOL.whitespace);
244 if boxed_split_without_method.is_none() {
245 return Err(Request::_ERROR_UNABLE_TO_PARSE_METHOD_AND_REQUEST_URI_AND_HTTP_VERSION.to_string())
246 }
247
248 let (method, without_method) = boxed_split_without_method.unwrap();
249 let supported_methods = Request::method_list();
250 if !supported_methods.contains(&method.to_uppercase().to_string()) {
251 return Err(Request::_ERROR_UNABLE_TO_PARSE_METHOD_AND_REQUEST_URI_AND_HTTP_VERSION.to_string())
252 }
253
254 let boxed_without_method = without_method.split_once(SYMBOL.whitespace);
255 if boxed_without_method.is_none() {
256 return Err(Request::_ERROR_UNABLE_TO_PARSE_METHOD_AND_REQUEST_URI_AND_HTTP_VERSION.to_string())
257 }
258
259 let (request_uri, http_version) = boxed_without_method.unwrap();
260
261
262 let supported_http_versions = HTTP::version_list();
263 if !supported_http_versions.contains(&http_version.to_uppercase().to_string()) {
264 return Err(Request::_ERROR_UNABLE_TO_PARSE_METHOD_AND_REQUEST_URI_AND_HTTP_VERSION.to_string())
265 }
266
267 Ok((method.to_string(), request_uri.to_string(), http_version.to_string()))
268
269 }
270
271 pub fn parse_http_request_header_string(header_string: &str) -> Header {
272 let header_parts: Vec<&str> = header_string.split(Header::NAME_VALUE_SEPARATOR).collect();
273 let header_name = StringExt::truncate_new_line_carriage_return(header_parts[0]);
274 let mut header_value= "".to_string();
275 if header_parts.get(1).is_some() {
276 header_value = StringExt::truncate_new_line_carriage_return(header_parts[1]);
277 }
278
279 Header {
280 name: header_name,
281 value: header_value,
282 }
283 }
284
285 pub fn cursor_read(cursor: &mut Cursor<&[u8]>, mut iteration_number: usize, request: &mut Request, mut content_length: usize) -> Result<bool, String> {
286 let mut buf = vec![];
287 let bytes_offset = cursor.read_until(b'\n', &mut buf).unwrap();
288 let b : &[u8] = &buf;
289 let boxed_request = String::from_utf8(Vec::from(b));
290 if boxed_request.is_err() {
291 let error_message = boxed_request.err().unwrap().to_string();
292 return Err(error_message);
293 }
294 let string = boxed_request.unwrap();
295
296 let is_first_iteration = iteration_number == 0;
297 let new_line_char_found = bytes_offset != 0;
298 let current_string_is_empty = string.trim().len() == 0;
299
300 if is_first_iteration {
301 match Request::parse_method_and_request_uri_and_http_version_string(&string) {
302 Ok((method, request_uri, http_version)) => {
303 request.method = method;
304 request.request_uri = request_uri;
305 request.http_version = http_version;
306 }
307 Err(error_message) => {
308 return Err(error_message)
309 }
310 }
311 }
312
313 if current_string_is_empty {
314 return Ok(true);
315 }
316
317 if new_line_char_found && !current_string_is_empty {
318 let mut header = Header { name: "".to_string(), value: "".to_string() };
319 if !is_first_iteration {
320 header = Request::parse_http_request_header_string(&string);
321 if header.name == Header::_CONTENT_LENGTH {
322 content_length = header.value.parse().unwrap();
323 }
324 }
325
326 request.headers.push(header);
327 iteration_number += 1;
328 let boxed_read = Request::cursor_read(cursor, iteration_number, request, content_length);
329 if boxed_read.is_err() {
330 let reason = boxed_read.err().unwrap().to_string();
331 eprintln!("unable to read request: {}", reason);
332 }
333 }
334
335 let mut buf = vec![];
338 let _ = cursor.read_to_end(&mut buf).unwrap();
339 let b : &[u8] = &buf;
340
341 request.body.append(&mut Vec::from(b));Ok(true)
344 }
345
346}
347
348impl std::fmt::Display for Request {
349 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
350 write!(fmt, "Request method {} and request uri {} and http_version {}", self.method, self.request_uri, self.http_version)
351 }
352}