http_type/request/impl.rs
1use crate::*;
2
3impl Default for Request {
4 fn default() -> Self {
5 Self {
6 method: Method::default(),
7 host: String::new(),
8 version: HttpVersion::default(),
9 path: String::new(),
10 querys: hash_map_xx_hash3_64(),
11 headers: hash_map_xx_hash3_64(),
12 body: Vec::new(),
13 }
14 }
15}
16
17impl Request {
18 /// Creates a new `Request` object from a TCP stream.
19 ///
20 /// # Parameters
21 /// - `reader`: A mut reference to a `&mut BufReader<&mut TcpStream>`.
22 /// - `buffer_size`: Request buffer size.
23 ///
24 /// # Returns
25 /// - `Ok`: A `Request` object populated with the HTTP request data.
26 /// - `Err`: An `RequestError` if the request is invalid or cannot be read.
27 pub async fn http_from_reader(
28 reader: &mut BufReader<&mut TcpStream>,
29 buffer_size: usize,
30 ) -> RequestReaderHandleResult {
31 let mut request_line: String = String::with_capacity(buffer_size);
32 let _ = AsyncBufReadExt::read_line(reader, &mut request_line).await;
33 let parts: Vec<&str> = request_line.split_whitespace().collect();
34 let parts_len: usize = parts.len();
35 if parts_len < 3 {
36 return Err(RequestError::InvalidHttpRequestPartsLength(parts_len));
37 }
38 let method: RequestMethod = parts[0].parse::<RequestMethod>().unwrap_or_default();
39 let full_path: RequestPath = parts[1].to_string();
40 let version: RequestVersion = parts[2].parse::<RequestVersion>().unwrap_or_default();
41 let hash_index: OptionUsize = full_path.find(HASH_SYMBOL);
42 let query_index: OptionUsize = full_path.find(QUERY_SYMBOL);
43 let query_string: String = query_index.map_or(String::new(), |i| {
44 let temp: &str = &full_path[i + 1..];
45 if hash_index.is_none() || hash_index.unwrap() <= i {
46 return temp.to_string();
47 }
48 temp.split(HASH_SYMBOL)
49 .next()
50 .unwrap_or_default()
51 .to_string()
52 });
53 let querys: RequestQuerys = Self::parse_querys(&query_string);
54 let path: RequestPath = if let Some(i) = query_index.or(hash_index) {
55 full_path[..i].to_string()
56 } else {
57 full_path
58 };
59 let mut headers: RequestHeaders = hash_map_xx_hash3_64();
60 let mut host: RequestHost = String::new();
61 let mut content_length: usize = 0;
62 loop {
63 let mut header_line: String = String::with_capacity(buffer_size);
64 let _ = AsyncBufReadExt::read_line(reader, &mut header_line).await;
65 let header_line: &str = header_line.trim();
66 if header_line.is_empty() {
67 break;
68 }
69 if let Some((key_part, value_part)) = header_line.split_once(COLON_SPACE_SYMBOL) {
70 let key: String = key_part.trim().to_ascii_lowercase();
71 let value: String = value_part.trim().to_string();
72 if key == HOST {
73 host = value.clone();
74 } else if key == CONTENT_LENGTH {
75 content_length = value.parse().unwrap_or(0);
76 }
77 headers.insert(key, value);
78 }
79 }
80 let mut body: RequestBody = vec![0; content_length];
81 if content_length > 0 {
82 let _ = AsyncReadExt::read_exact(reader, &mut body).await;
83 }
84 Ok(Request {
85 method,
86 host,
87 version,
88 path,
89 querys,
90 headers,
91 body,
92 })
93 }
94
95 /// Creates a new `Request` object from a TCP stream.
96 ///
97 /// # Parameters
98 /// - `stream`: A reference to a `&ArcRwLockStream` representing the incoming connection.
99 /// - `buffer_size`: Request buffer size.
100 ///
101 /// # Returns
102 /// - `Ok`: A `Request` object populated with the HTTP request data.
103 /// - `Err`: An `RequestError` if the request is invalid or cannot be read.
104 pub async fn http_request_from_stream(
105 stream: &ArcRwLockStream,
106 buffer_size: usize,
107 ) -> RequestReaderHandleResult {
108 let mut buf_stream: RwLockWriteGuard<'_, TcpStream> = stream.write().await;
109 let mut reader: BufReader<&mut TcpStream> = BufReader::new(&mut buf_stream);
110 Self::http_from_reader(&mut reader, buffer_size).await
111 }
112
113 /// Creates a new `Request` object from a TCP stream.
114 ///
115 /// # Parameters
116 /// - `stream`: A reference to a `&ArcRwLockStream` representing the incoming connection.
117 /// - `buffer_size`: Request buffer size.
118 /// - `request`: A reference to a `Request` object. This object is used as a template.
119 ///
120 /// # Returns
121 /// - `Ok`: A `Request` object populated with the HTTP request data.
122 /// - `Err`: An `RequestError` if the request is invalid or cannot be read.
123 pub async fn ws_request_from_stream(
124 stream: &ArcRwLockStream,
125 buffer_size: usize,
126 request: &mut Self,
127 ) -> RequestReaderHandleResult {
128 let mut buf_stream: RwLockWriteGuard<'_, TcpStream> = stream.write().await;
129 let mut reader: BufReader<&mut TcpStream> = BufReader::new(&mut buf_stream);
130 Self::ws_from_reader(&mut reader, buffer_size, request).await
131 }
132
133 /// Reads a WebSocket request from a TCP stream and constructs a `Request` object.
134 ///
135 /// This function reads data from the provided `BufReader` wrapped around a `TcpStream`.
136 /// It attempts to read up to 1024 bytes into a buffer and constructs a `Request` object
137 /// based on the received data. The request body is set using the received bytes.
138 ///
139 /// # Arguments
140 /// - `reader` - A mutable reference to a `BufReader` wrapping a `TcpStream`.
141 /// This reader is used to read the incoming WebSocket request data.
142 /// - `buffer_size`: - Request buffer size.
143 /// - `request` - A reference to a `Request` object. This object is used as a template.
144 ///
145 /// # Returns
146 /// - `Ok(Request)` - A `Request` object constructed from the received data.
147 /// - If no data is read (`Ok(0)`), an empty `Request` object is returned.
148 /// - If data is successfully read, the request body is set with the received bytes.
149 /// - `Err(RequestError::InvalidWebSocketRequest)` - If an error occurs while reading from the stream.
150 pub async fn ws_from_reader(
151 reader: &mut BufReader<&mut TcpStream>,
152 buffer_size: usize,
153 request: &mut Self,
154 ) -> RequestReaderHandleResult {
155 let mut dynamic_buffer: Vec<u8> = Vec::with_capacity(buffer_size);
156 let mut temp_buffer: Vec<u8> = vec![0; buffer_size];
157 let mut full_frame: Vec<u8> = Vec::new();
158 let mut error_handle = || {
159 request.body.clear();
160 };
161 loop {
162 let len: usize = match reader.read(&mut temp_buffer).await {
163 Ok(len) => len,
164 Err(err) => {
165 error_handle();
166 if err.kind() == ErrorKind::ConnectionReset
167 || err.kind() == ErrorKind::ConnectionAborted
168 {
169 return Err(RequestError::ClientDisconnected);
170 }
171 return Err(RequestError::InvalidWebSocketRequest(err.to_string()));
172 }
173 };
174 if len == 0 {
175 error_handle();
176 return Err(RequestError::IncompleteWebSocketFrame);
177 }
178 dynamic_buffer.extend_from_slice(&temp_buffer[..len]);
179 while let Some((frame, consumed)) = WebSocketFrame::decode_ws_frame(&dynamic_buffer) {
180 dynamic_buffer.drain(0..consumed);
181 match frame.get_opcode() {
182 WebSocketOpcode::Close => {
183 error_handle();
184 return Err(RequestError::ClientClosedConnection);
185 }
186 WebSocketOpcode::Ping | WebSocketOpcode::Pong => {
187 continue;
188 }
189 WebSocketOpcode::Text | WebSocketOpcode::Binary => {
190 full_frame.extend_from_slice(frame.get_payload_data());
191 if *frame.get_fin() {
192 let mut request: Request = request.clone();
193 request.body = full_frame;
194 return Ok(request);
195 }
196 }
197 _ => {
198 error_handle();
199 return Err(RequestError::InvalidWebSocketFrame(
200 "Unsupported opcode".into(),
201 ));
202 }
203 }
204 }
205 }
206 }
207
208 /// Parse querys
209 ///
210 /// # Parameters
211 /// - `query`: &str
212 ///
213 /// # Returns
214 /// - RequestQuerys
215 fn parse_querys(query: &str) -> RequestQuerys {
216 let mut query_map: RequestQuerys = hash_map_xx_hash3_64();
217 for pair in query.split(AND) {
218 if let Some((key, value)) = pair.split_once(EQUAL) {
219 if !key.is_empty() {
220 query_map.insert(key.to_string(), value.to_string());
221 }
222 } else if !pair.is_empty() {
223 query_map.insert(pair.to_string(), String::new());
224 }
225 }
226 query_map
227 }
228
229 /// Retrieves the value of a query parameter by its key.
230 ///
231 /// # Parameters
232 /// - `key`: The query parameter's key, which can be of any type that implements `Into<RequestQuerysKey>`.
233 ///
234 /// # Returns
235 /// - `OptionRequestQuerysValue`: Returns `Some(value)` if the key exists in the query parameters,
236 /// or `None` if the key does not exist.
237 pub fn get_query<K>(&self, key: K) -> OptionRequestQuerysValue
238 where
239 K: Into<RequestQuerysKey>,
240 {
241 self.querys.get(&key.into()).cloned()
242 }
243
244 /// Retrieves the value of a request header by its key.
245 ///
246 /// # Parameters
247 /// - `key`: The header's key, which can be of any type that implements `Into<RequestHeadersKey>`.
248 ///
249 /// # Returns
250 /// - `OptionRequestHeadersValue`: Returns `Some(value)` if the key exists in the request headers,
251 /// or `None` if the key does not exist.
252 pub fn get_header<K>(&self, key: K) -> OptionRequestHeadersValue
253 where
254 K: Into<RequestHeadersKey>,
255 {
256 self.headers.get(&key.into()).cloned()
257 }
258
259 /// Retrieves the body content of the object as a UTF-8 encoded string.
260 ///
261 /// This method uses `String::from_utf8_lossy` to convert the byte slice returned by `self.get_body()` into a string.
262 /// If the byte slice contains invalid UTF-8 sequences, they will be replaced with the Unicode replacement character (�).
263 ///
264 /// # Returns
265 /// A `String` containing the body content.
266 pub fn get_body_string(&self) -> String {
267 String::from_utf8_lossy(self.get_body()).into_owned()
268 }
269
270 /// Deserializes the body content of the object into a specified type `T`.
271 ///
272 /// This method first retrieves the body content as a UTF-8 encoded string using `self.get_body()`.
273 /// It then attempts to deserialize the string into the specified type `T` using `json_from_slice`.
274 ///
275 /// # Type Parameters
276 /// - `T`: The target type to deserialize into. It must implement the `DeserializeOwned` trait.
277 ///
278 /// # Returns
279 /// - `Ok(T)`: The deserialized object of type `T` if the deserialization is successful.
280 /// - `Err(ResultJsonError)`: An error if the deserialization fails (e.g., invalid JSON format or type mismatch).
281 pub fn get_body_json<T>(&self) -> ResultJsonError<T>
282 where
283 T: DeserializeOwned,
284 {
285 json_from_slice(self.get_body())
286 }
287
288 /// Converts the request to a formatted string representation.
289 ///
290 /// - Returns: A `String` containing formatted request details.
291 pub fn get_string(&self) -> String {
292 let body: &Vec<u8> = self.get_body();
293 let body_display: Cow<'_, str> = match std::str::from_utf8(body) {
294 Ok(string_data) => Cow::Borrowed(string_data),
295 Err(_) => Cow::Owned(format!("binary data len: {}", body.len())),
296 };
297 format!(
298 "[Request] => [Method]: {}; [Host]: {}; [Version]: {}; [Path]: {}; [Querys]: {:?}; [Headers]: {:?}; [Body]: {};",
299 self.get_method(),
300 self.get_host(),
301 self.get_version(),
302 self.get_path(),
303 self.get_querys(),
304 self.get_headers(),
305 body_display,
306 )
307 }
308
309 /// Retrieves the upgrade type from the request headers.
310 ///
311 /// - Returns: The `UpgradeType` extracted from the `UPGRADE` header.
312 /// If the header is missing or invalid, returns the default `UpgradeType`.
313 pub fn get_upgrade_type(&self) -> UpgradeType {
314 let upgrade_type: UpgradeType = self
315 .get_header(UPGRADE)
316 .and_then(|data| data.parse::<UpgradeType>().ok())
317 .unwrap_or_default();
318 upgrade_type
319 }
320
321 /// Checks whether the WebSocket upgrade is enabled.
322 ///
323 /// - Returns: `true` if the upgrade type is WebSocket; otherwise, `false`.
324 pub fn is_ws(&self) -> bool {
325 self.get_upgrade_type().is_ws()
326 }
327
328 /// Checks if the current upgrade type is HTTP/2 cleartext (h2c).
329 ///
330 /// - `&self` - The current instance (usually a request or context struct).
331 ///
332 /// - Returns `true` if the upgrade type is `h2c`, otherwise `false`.
333 pub fn is_h2c(&self) -> bool {
334 self.get_upgrade_type().is_h2c()
335 }
336
337 /// Checks if the current upgrade type is TLS (any version).
338 ///
339 /// - `&self` - The current instance (usually a request or context struct).
340 ///
341 /// - Returns `true` if the upgrade type is any `Tls` variant, otherwise `false`.
342 pub fn is_tls(&self) -> bool {
343 self.get_upgrade_type().is_tls()
344 }
345
346 /// Checks whether the upgrade type is unknown.
347 ///
348 /// - Returns: `true` if the upgrade type is unknown; otherwise, `false`.
349 pub fn is_unknown_upgrade(&self) -> bool {
350 self.get_upgrade_type().is_unknown()
351 }
352
353 /// Checks if the HTTP version is HTTP/1.1 or higher.
354 ///
355 /// - Returns: `true` if the HTTP version is 1.1 or higher; otherwise, `false`.
356 pub fn is_http1_1_or_higher(&self) -> bool {
357 self.get_version().is_http1_1_or_higher()
358 }
359
360 /// Checks whether the HTTP version is HTTP/0.9.
361 ///
362 /// - Returns: `true` if the version is HTTP/0.9; otherwise, `false`.
363 pub fn is_http0_9(&self) -> bool {
364 self.get_version().is_http0_9()
365 }
366
367 /// Checks whether the HTTP version is HTTP/1.0.
368 ///
369 /// - Returns: `true` if the version is HTTP/1.0; otherwise, `false`.
370 pub fn is_http1_0(&self) -> bool {
371 self.get_version().is_http1_0()
372 }
373
374 /// Checks whether the HTTP version is HTTP/1.1.
375 ///
376 /// - Returns: `true` if the version is HTTP/1.1; otherwise, `false`.
377 pub fn is_http1_1(&self) -> bool {
378 self.get_version().is_http1_1()
379 }
380
381 /// Checks whether the HTTP version is HTTP/2.
382 ///
383 /// - Returns: `true` if the version is HTTP/2; otherwise, `false`.
384 pub fn is_http2(&self) -> bool {
385 self.get_version().is_http2()
386 }
387
388 /// Checks whether the HTTP version is HTTP/3.
389 ///
390 /// - Returns: `true` if the version is HTTP/3; otherwise, `false`.
391 pub fn is_http3(&self) -> bool {
392 self.get_version().is_http3()
393 }
394
395 /// Checks whether the HTTP version is unknown.
396 ///
397 /// - Returns: `true` if the version is unknown; otherwise, `false`.
398 pub fn is_unknown_version(&self) -> bool {
399 self.get_version().is_unknown()
400 }
401
402 /// Checks whether the version belongs to the HTTP family.
403 ///
404 /// - Returns: `true` if the version is a valid HTTP version; otherwise, `false`.
405 pub fn is_http(&self) -> bool {
406 self.get_version().is_http()
407 }
408
409 /// Checks whether the request method is `GET`.
410 ///
411 /// - Returns: `true` if the method is `GET`; otherwise, `false`.
412 pub fn is_get(&self) -> bool {
413 self.get_method().is_get()
414 }
415
416 /// Checks whether the request method is `POST`.
417 ///
418 /// - Returns: `true` if the method is `POST`; otherwise, `false`.
419 pub fn is_post(&self) -> bool {
420 self.get_method().is_post()
421 }
422
423 /// Checks whether the request method is `PUT`.
424 ///
425 /// - Returns: `true` if the method is `PUT`; otherwise, `false`.
426 pub fn is_put(&self) -> bool {
427 self.get_method().is_put()
428 }
429
430 /// Checks whether the request method is `DELETE`.
431 ///
432 /// - Returns: `true` if the method is `DELETE`; otherwise, `false`.
433 pub fn is_delete(&self) -> bool {
434 self.get_method().is_delete()
435 }
436
437 /// Checks whether the request method is `PATCH`.
438 ///
439 /// - Returns: `true` if the method is `PATCH`; otherwise, `false`.
440 pub fn is_patch(&self) -> bool {
441 self.get_method().is_patch()
442 }
443
444 /// Checks whether the request method is `HEAD`.
445 ///
446 /// - Returns: `true` if the method is `HEAD`; otherwise, `false`.
447 pub fn is_head(&self) -> bool {
448 self.get_method().is_head()
449 }
450
451 /// Checks whether the request method is `OPTIONS`.
452 ///
453 /// - Returns: `true` if the method is `OPTIONS`; otherwise, `false`.
454 pub fn is_options(&self) -> bool {
455 self.get_method().is_options()
456 }
457
458 /// Checks whether the request method is `CONNECT`.
459 ///
460 /// - Returns: `true` if the method is `CONNECT`; otherwise, `false`.
461 pub fn is_connect(&self) -> bool {
462 self.get_method().is_connect()
463 }
464
465 /// Checks whether the request method is `TRACE`.
466 ///
467 /// - Returns: `true` if the method is `TRACE`; otherwise, `false`.
468 pub fn is_trace(&self) -> bool {
469 self.get_method().is_trace()
470 }
471
472 /// Checks whether the request method is `UNKNOWN`.
473 ///
474 /// - Returns: `true` if the method is `UNKNOWN`; otherwise, `false`.
475 pub fn is_unknown_method(&self) -> bool {
476 self.get_method().is_unknown()
477 }
478
479 /// Determines if keep-alive connection should be enabled for this request.
480 ///
481 /// This function checks the Connection header and HTTP version to determine if
482 /// keep-alive should be enabled. The logic is as follows:
483 ///
484 /// 1. If Connection header exists:
485 /// - Returns true if header value is "keep-alive"
486 /// - Returns false if header value is "close"
487 /// 2. If no Connection header:
488 /// - Returns true if HTTP version is 1.1 or higher
489 /// - Returns false otherwise
490 ///
491 /// # Returns
492 /// - `bool`: true if keep-alive should be enabled, false otherwise
493 pub fn is_enable_keep_alive(&self) -> bool {
494 if let Some(connection_value) = self.get_header(CONNECTION) {
495 if connection_value.eq_ignore_ascii_case(KEEP_ALIVE) {
496 return true;
497 } else if connection_value.eq_ignore_ascii_case(CLOSE) {
498 return self.is_ws();
499 }
500 }
501 self.is_http1_1_or_higher() || self.is_ws()
502 }
503}