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