pillow_http/request/
mod.rs

1use std::collections::HashMap;
2use std::fmt;
3
4use crate::header::Header;
5use crate::http_methods::HttpMethods;
6use crate::uri::Uri;
7
8use crate::body::Body;
9
10/// Http Request
11#[derive(Debug, Clone)]
12pub struct Request {
13    method: HttpMethods,
14    version: String,
15    headers: HashMap<Header, String>,
16    uri: Uri,
17    params: HashMap<String, String>,
18    body: Body,
19}
20
21impl Default for Request {
22    fn default() -> Self {
23        Self::new_empty()
24    }
25}
26
27impl Request {
28    /// Instance empty Request
29    pub fn new_empty() -> Self {
30        Self {
31            method: HttpMethods::GET,
32            version: "HTTP/1.1".to_string(),
33            headers: HashMap::new(),
34            uri: Uri("".to_string()),
35            params: HashMap::new(),
36            body: Body::NONE,
37        }
38    }
39}
40
41impl Request {
42    /// http method reference
43    pub fn method(&self) -> &HttpMethods {
44        &self.method
45    }
46
47    /// version reference
48    pub fn version(&self) -> &String {
49        &self.version
50    }
51
52    /// uri reference
53    pub fn uri(&self) -> &Uri {
54        &self.uri
55    }
56
57    /// Headers reference
58    pub fn headers(&self) -> &HashMap<Header, String> {
59        &self.headers
60    }
61
62    /// Params reference
63    pub fn params(&self) -> &HashMap<String, String> {
64        &self.params
65    }
66
67    /// Body reference
68    pub fn body(&self) -> &Body {
69        &self.body
70    }
71}
72
73impl Request {
74    pub fn add_params(&mut self, params: (String, String)) {
75        self.params.insert(params.0, params.1);
76    }
77}
78
79impl Request {
80    /// Create a Request from &Vec<u8>
81    ///
82    /// # Arguments
83    ///
84    /// * data - Is a data from a stream
85    pub fn from_vec(data: &Vec<u8>) -> Result<Request, std::str::Utf8Error> {
86        let request_str_full = Self::from_vec_to_str(data)?;
87
88        let mut req_vec: Vec<&str> = request_str_full.split("\n").collect();
89
90        let (method_str, uri_str, version_str) = Self::separate_method_uri_version(req_vec[0]);
91
92        let method = crate::http_methods::from_str_to_http_method(method_str).unwrap();
93        let uri = Self::get_uri(uri_str);
94
95        let params = match Self::get_params(uri_str) {
96            Some(hashmap) => hashmap,
97            None => HashMap::new(),
98        };
99
100        let headers = Self::get_headers(&mut req_vec);
101        let body = Self::get_body(req_vec, headers.len());
102
103        Ok(Self {
104            method,
105            version: version_str.to_string(),
106            uri,
107            headers,
108            params,
109            body,
110        })
111    }
112
113    /// Create a body from a Vec<&str>
114    ///
115    /// # Arguments
116    ///
117    /// * header_vec - All header in a request
118    ///
119    /// * lenght - body lenght
120    fn get_body(headers_vec: Vec<&str>, lenght: usize) -> crate::body::Body {
121        let mut body_vec: Vec<Vec<&str>> = headers_vec.chunks(lenght).map(|x| x.into()).collect();
122        body_vec.remove(0);
123
124        let body_vec = body_vec[0].clone();
125
126        let mut body = String::new();
127
128        for body_items in &body_vec {
129            if !body_vec.is_empty() {
130                body = body + body_items;
131            }
132        }
133
134        let body = Self::remove_0(&body);
135
136        crate::body::from_string_to_body(body.to_string())
137    }
138
139    /// Remove a 0 in last part from request
140    ///
141    /// # Arguments
142    ///
143    /// * string - String where delete 0
144    fn remove_0(string: &String) -> &str {
145        let vec_str: Vec<&str> = string.split("\0").collect();
146
147        vec_str[0]
148    }
149
150    /// Get a headers
151    fn get_headers(headers_vec: &mut Vec<&str>) -> HashMap<Header, String> {
152        headers_vec.remove(0);
153
154        let mut header_hash_map = HashMap::new();
155
156        for header in headers_vec {
157            let key_value_vec: Vec<&str> = header.split(":").map(|x| x.trim()).collect();
158
159            if key_value_vec.len() > 1 {
160                let key = crate::header::from_string_to_header(key_value_vec[0].to_string());
161                let value = key_value_vec[1].to_string();
162
163                if key_value_vec.len() > 2 {
164                    let value = value + key_value_vec[2];
165                    header_hash_map.insert(key, value);
166                } else {
167                    header_hash_map.insert(key, value);
168                }
169            }
170        }
171
172        header_hash_map
173    }
174
175    /// Separate method, uri, version from a all string request
176    fn separate_method_uri_version(header: &str) -> (&str, &str, &str) {
177        let header_vec: Vec<&str> = header.split_whitespace().collect();
178
179        if header_vec.len() < 2 {
180            panic!("Err in get header or uri or version");
181        }
182
183        (header_vec[0], header_vec[1], header_vec[2])
184    }
185
186    /// Convert data to Result of &str is a request
187    fn from_vec_to_str(data: &Vec<u8>) -> Result<&str, std::str::Utf8Error> {
188        std::str::from_utf8(data)
189    }
190
191    /// Convert &str to Uri struct
192    fn get_uri(uri_str: &str) -> Uri {
193        let uri_vec: Vec<&str> = uri_str.split("?").collect();
194
195        Uri(uri_vec[0].to_string())
196    }
197
198    /// Get params in the uri
199    fn get_params(uri: &str) -> Option<HashMap<String, String>> {
200        let mut params_vec: Vec<&str> = uri.split("?").collect();
201        let mut params_hash_map = HashMap::new();
202
203        if params_vec.len() > 1 {
204            params_vec.remove(0);
205
206            let params_vec: Vec<&str> = params_vec[0].split("&").collect();
207
208            for params in params_vec {
209                let p_vec: Vec<&str> = params.split("=").collect();
210
211                params_hash_map.insert(p_vec[0].to_string(), p_vec[1].to_string());
212            }
213
214            return Some(params_hash_map);
215        }
216
217        None
218    }
219}
220
221impl Request {
222    pub fn get_param(&self, param: &'static str) -> String {
223        self.params.get(param).unwrap().clone()
224    }
225}
226
227impl fmt::Display for Request {
228    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229        f.debug_struct("Request")
230            .field("method", &self.method)
231            .field("version", &self.version)
232            .field("headers", &self.headers)
233            .field("uri", &self.uri)
234            .field("params", &self.params)
235            .field("body", &self.body)
236            .finish()
237    }
238}