http_type/request/
impl.rs

1use super::error::Error;
2use crate::*;
3use std::{
4    collections::HashMap,
5    io::{BufRead, BufReader, Read},
6    net::TcpStream,
7    str::SplitN,
8};
9
10impl Default for Request {
11    #[inline]
12    fn default() -> Self {
13        Self {
14            method: String::new(),
15            host: String::new(),
16            path: String::new(),
17            query: HashMap::new(),
18            headers: HashMap::new(),
19            body: Vec::new(),
20        }
21    }
22}
23
24impl Request {
25    /// Creates a new `Request` object from a TCP stream.
26    ///
27    /// # Parameters
28    /// - `reader`: A mut reference to a `&BufReader<&TcpStream>`
29    ///
30    /// # Returns
31    /// - `Ok`: A `Request` object populated with the HTTP request data.
32    /// - `Err`: An `Error` if the request is invalid or cannot be read.
33    #[inline]
34    pub fn from_reader(reader: &mut BufReader<&TcpStream>) -> RequestNewResult {
35        let mut request_line: String = String::new();
36        reader
37            .read_line(&mut request_line)
38            .map_err(|_| Error::HttpReadError)?;
39        let parts: Vec<&str> = request_line.split_whitespace().collect();
40        if parts.len() < 3 {
41            return Err(Error::InvalidHttpRequest);
42        }
43        let method: RequestMethod = parts[0].to_string();
44        let full_path: String = parts[1].to_string();
45        let hash_index: Option<usize> = full_path.find(HASH_SYMBOL);
46        let query_index: Option<usize> = full_path.find(QUERY_SYMBOL);
47        let query_string: String = query_index.map_or(EMPTY_STR.to_owned(), |i| {
48            let temp: String = full_path[i + 1..].to_string();
49            if hash_index.is_none() || hash_index.unwrap() <= i {
50                return temp.into();
51            }
52            let data: String = temp
53                .split(HASH_SYMBOL)
54                .next()
55                .unwrap_or_default()
56                .to_string();
57            data.into()
58        });
59        let query: RequestQuery = Self::parse_query(&query_string);
60        let path: RequestPath = if let Some(i) = query_index.or(hash_index) {
61            full_path[..i].to_string()
62        } else {
63            full_path
64        };
65        let mut headers: RequestHeaders = HashMap::new();
66        let mut host: RequestHost = EMPTY_STR.to_owned();
67        let mut content_length: usize = 0;
68        loop {
69            let mut header_line: String = String::new();
70            reader
71                .read_line(&mut header_line)
72                .map_err(|_| Error::HttpReadError)?;
73            let header_line: &str = header_line.trim();
74            if header_line.is_empty() {
75                break;
76            }
77            let parts: Vec<&str> = header_line.splitn(2, COLON_SPACE_SYMBOL).collect();
78            if parts.len() != 2 {
79                continue;
80            }
81            let key: String = parts[0].trim().to_string();
82            let value: String = parts[1].trim().to_string();
83            if key.eq_ignore_ascii_case(HOST) {
84                host = value.to_string();
85            }
86            if key.eq_ignore_ascii_case(CONTENT_LENGTH) {
87                content_length = value.parse().unwrap_or(0);
88            }
89            headers.insert(key, value);
90        }
91        let mut body: RequestBody = Vec::new();
92        if content_length > 0 {
93            body.resize(content_length, 0);
94            reader
95                .read_exact(&mut body)
96                .map_err(|_| Error::HttpReadError)?;
97        }
98        Ok(Request {
99            method,
100            host,
101            path,
102            query,
103            headers,
104            body,
105        })
106    }
107
108    /// Creates a new `Request` object from a TCP stream.
109    ///
110    /// # Parameters
111    /// - `stream`: A reference to a `&std::net::TcpStream` representing the incoming connection.
112    ///
113    /// # Returns
114    /// - `Ok`: A `Request` object populated with the HTTP request data.
115    /// - `Err`: An `Error` if the request is invalid or cannot be read.
116    #[inline]
117    pub fn from_stream(stream: &std::net::TcpStream) -> RequestNewResult {
118        let mut reader: BufReader<&TcpStream> = BufReader::new(&stream);
119        Self::from_reader(&mut reader)
120    }
121
122    /// Creates a new `Request` object from a TCP stream.
123    ///
124    /// # Parameters
125    /// - `stream`: A reference to a `&tokio::net::TcpStream` representing the incoming connection.
126    ///
127    /// # Returns
128    /// - `Ok`: A `Request` object populated with the HTTP request data.
129    /// - `Err`: An `Error` if the request is invalid or cannot be read.
130    #[inline]
131    pub async fn async_new(stream: &mut tokio::net::TcpStream) -> RequestNewResult {
132        use tokio::io::{AsyncBufReadExt, AsyncReadExt};
133        let mut reader: tokio::io::BufReader<&mut tokio::net::TcpStream> =
134            tokio::io::BufReader::new(stream);
135        let mut request_line = String::new();
136        reader
137            .read_line(&mut request_line)
138            .await
139            .map_err(|_| Error::HttpReadError)?;
140        let parts: Vec<&str> = request_line.split_whitespace().collect();
141        if parts.len() < 3 {
142            return Err(Error::InvalidHttpRequest);
143        }
144        let method: RequestMethod = parts[0].to_string();
145        let full_path: String = parts[1].to_string();
146        let hash_index: Option<usize> = full_path.find(HASH_SYMBOL);
147        let query_index: Option<usize> = full_path.find(QUERY_SYMBOL);
148        let query_string: String = query_index.map_or(EMPTY_STR.to_owned(), |i| {
149            let temp: String = full_path[i + 1..].to_string();
150            if hash_index.is_none() || hash_index.unwrap() <= i {
151                return temp.into();
152            }
153            let data: String = temp
154                .split(HASH_SYMBOL)
155                .next()
156                .unwrap_or_default()
157                .to_string();
158            data.into()
159        });
160        let query: RequestQuery = Self::parse_query(&query_string);
161        let path: RequestPath = if let Some(i) = query_index.or(hash_index) {
162            full_path[..i].to_string()
163        } else {
164            full_path
165        };
166        let mut headers: RequestHeaders = HashMap::new();
167        let mut host: RequestHost = EMPTY_STR.to_owned();
168        let mut content_length: usize = 0;
169        loop {
170            let mut header_line: String = String::new();
171            reader
172                .read_line(&mut header_line)
173                .await
174                .map_err(|_| Error::HttpReadError)?;
175
176            let header_line: &str = header_line.trim();
177            if header_line.is_empty() {
178                break;
179            }
180            let parts: Vec<&str> = header_line.splitn(2, COLON_SPACE_SYMBOL).collect();
181            if parts.len() != 2 {
182                continue;
183            }
184            let key: String = parts[0].trim().to_string();
185            let value: String = parts[1].trim().to_string();
186            if key.eq_ignore_ascii_case(HOST) {
187                host = value.to_string();
188            }
189            if key.eq_ignore_ascii_case(CONTENT_LENGTH) {
190                content_length = value.parse().unwrap_or(0);
191            }
192            headers.insert(key, value);
193        }
194        let mut body: RequestBody = Vec::new();
195        if content_length > 0 {
196            body.resize(content_length, 0);
197            reader
198                .read_exact(&mut body)
199                .await
200                .map_err(|_| Error::HttpReadError)?;
201        }
202        Ok(Request {
203            method,
204            host,
205            path,
206            query,
207            headers,
208            body,
209        })
210    }
211
212    /// Parse query
213    ///
214    /// # Parameters
215    /// - `query`: &str
216    ///
217    /// # Returns
218    /// - RequestQuery
219    #[inline]
220    fn parse_query(query: &str) -> RequestQuery {
221        let mut query_map: RequestQuery = HashMap::new();
222        for pair in query.split(AND) {
223            let mut parts: SplitN<'_, &str> = pair.splitn(2, EQUAL);
224            let key: String = parts.next().unwrap_or_default().to_string();
225            let value: String = parts.next().unwrap_or_default().to_string();
226            if !key.is_empty() {
227                query_map.insert(key, value);
228            }
229        }
230        query_map
231    }
232
233    /// Adds a header to the request.
234    ///
235    /// This function inserts a key-value pair into the request headers.
236    /// The key and value are converted into `String`, allowing for efficient handling of both owned and borrowed string data.
237    ///
238    /// # Parameters
239    /// - `key`: The header key, which will be converted into a `String`.
240    /// - `value`: The value of the header, which will be converted into a `String`.
241    ///
242    /// # Returns
243    /// - Returns a mutable reference to the current instance (`&mut Self`), allowing for method chaining.
244    #[inline]
245    pub fn set_header<K, V>(&mut self, key: K, value: V) -> &mut Self
246    where
247        K: Into<String>,
248        V: Into<String>,
249    {
250        self.headers.insert(key.into(), value.into());
251        self
252    }
253
254    /// Set the body of the response.
255    ///
256    /// This method allows you to set the body of the response by converting the provided
257    /// value into a `RequestBody` type. The `body` is updated with the converted value,
258    /// and the method returns a mutable reference to the current instance for method chaining.
259    ///
260    /// # Parameters
261    /// - `body`: The body of the response to be set. It can be any type that can be converted
262    ///   into a `RequestBody` using the `Into` trait.
263    ///
264    /// # Return Value
265    /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
266    /// Set the body of the response.
267    ///
268    /// This method allows you to set the body of the response by converting the provided
269    /// value into a `RequestBody` type. The `body` is updated with the converted value,
270    /// and the method returns a mutable reference to the current instance for method chaining.
271    ///
272    /// # Parameters
273    /// - `body`: The body of the response to be set. It can be any type that can be converted
274    ///   into a `RequestBody` using the `Into` trait.
275    ///
276    /// # Return Value
277    /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
278    #[inline]
279    pub fn set_body<T: Into<RequestBody>>(&mut self, body: T) -> &mut Self {
280        self.body = body.into();
281        self
282    }
283
284    /// Set the HTTP method of the request.
285    ///
286    /// This method allows you to set the HTTP method (e.g., GET, POST) of the request
287    /// by converting the provided value into a `RequestMethod` type. The `method` is updated
288    /// with the converted value, and the method returns a mutable reference to the current
289    /// instance for method chaining.
290    ///
291    /// # Parameters
292    /// - `method`: The HTTP method to be set for the request. It can be any type that can
293    ///   be converted into a `RequestMethod` using the `Into` trait.
294    ///
295    /// # Return Value
296    /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
297    #[inline]
298    pub fn set_method<T: Into<RequestMethod>>(&mut self, method: T) -> &mut Self {
299        self.method = method.into();
300        self
301    }
302
303    /// Set the host of the request.
304    ///
305    /// This method allows you to set the host (e.g., www.example.com) for the request
306    /// by converting the provided value into a `RequestHost` type. The `host` is updated
307    /// with the converted value, and the method returns a mutable reference to the current
308    /// instance for method chaining.
309    ///
310    /// # Parameters
311    /// - `host`: The host to be set for the request. It can be any type that can be converted
312    ///   into a `RequestHost` using the `Into` trait.
313    ///
314    /// # Return Value
315    /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
316    #[inline]
317    pub fn set_host<T: Into<RequestHost>>(&mut self, host: T) -> &mut Self {
318        self.host = host.into();
319        self
320    }
321
322    /// Set the path of the request.
323    ///
324    /// This method allows you to set the path (e.g., /api/v1/resource) for the request
325    /// by converting the provided value into a `RequestPath` type. The `path` is updated
326    /// with the converted value, and the method returns a mutable reference to the current
327    /// instance for method chaining.
328    ///
329    /// # Parameters
330    /// - `path`: The path to be set for the request. It can be any type that can be converted
331    ///   into a `RequestPath` using the `Into` trait.
332    ///
333    /// # Return Value
334    /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
335    #[inline]
336    pub fn set_path<T: Into<RequestPath>>(&mut self, path: T) -> &mut Self {
337        self.path = path.into();
338        self
339    }
340
341    /// Set the query string of the request.
342    ///
343    /// This method allows you to set the query string (e.g., ?key=value) for the request
344    /// by converting the provided value into a `RequestQuery` type. The `query` is updated
345    /// with the converted value, and the method returns a mutable reference to the current
346    /// instance for method chaining.
347    ///
348    /// # Parameters
349    /// - `query`: The query string to be set for the request. It can be any type that can
350    ///   be converted into a `RequestQuery` using the `Into` trait.
351    ///
352    /// # Return Value
353    /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
354    #[inline]
355    pub fn set_query<T: Into<RequestQuery>>(&mut self, query: T) -> &mut Self {
356        self.query = query.into();
357        self
358    }
359}