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