http_type/request/
impl.rs

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