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}