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                if key.is_empty() {
72                    continue;
73                }
74                let value: String = value_part.trim().to_string();
75                if key == HOST {
76                    host = value.clone();
77                } else if key == CONTENT_LENGTH {
78                    content_length = value.parse().unwrap_or(0);
79                }
80                headers
81                    .entry(key)
82                    .or_insert_with(VecDeque::new)
83                    .push_back(value);
84            }
85        }
86        let mut body: RequestBody = vec![0; content_length];
87        if content_length > 0 {
88            let _ = AsyncReadExt::read_exact(reader, &mut body).await;
89        }
90        Ok(Request {
91            method,
92            host,
93            version,
94            path,
95            querys,
96            headers,
97            body,
98        })
99    }
100
101    /// Creates a new `Request` object from a TCP stream.
102    ///
103    /// # Parameters
104    /// - `stream`: A reference to a `&ArcRwLockStream` representing the incoming connection.
105    /// - `buffer_size`: Request buffer size.
106    ///
107    /// # Returns
108    /// - `Ok`: A `Request` object populated with the HTTP request data.
109    /// - `Err`: An `RequestError` if the request is invalid or cannot be read.
110    pub async fn http_from_stream(
111        stream: &ArcRwLockStream,
112        buffer_size: usize,
113    ) -> RequestReaderHandleResult {
114        let mut buf_stream: RwLockWriteGuard<'_, TcpStream> = stream.write().await;
115        let mut reader: BufReader<&mut TcpStream> = BufReader::new(&mut buf_stream);
116        Self::http_from_reader(&mut reader, buffer_size).await
117    }
118
119    /// Creates a new `Request` object from a TCP stream.
120    ///
121    /// # Parameters
122    /// - `stream`: A reference to a `&ArcRwLockStream` representing the incoming connection.
123    /// - `buffer_size`: Request buffer size.
124    /// - `request`: A reference to a `Request` object. This object is used as a template.
125    ///
126    /// # Returns
127    /// - `Ok`: A `Request` object populated with the HTTP request data.
128    /// - `Err`: An `RequestError` if the request is invalid or cannot be read.
129    pub async fn ws_from_stream(
130        stream: &ArcRwLockStream,
131        buffer_size: usize,
132        request: &mut Self,
133    ) -> RequestReaderHandleResult {
134        let mut buf_stream: RwLockWriteGuard<'_, TcpStream> = stream.write().await;
135        let mut reader: BufReader<&mut TcpStream> = BufReader::new(&mut buf_stream);
136        Self::ws_from_reader(&mut reader, buffer_size, request).await
137    }
138
139    /// Reads a WebSocket request from a TCP stream and constructs a `Request` object.
140    ///
141    /// This function reads data from the provided `BufReader` wrapped around a `TcpStream`.
142    /// It attempts to read up to 1024 bytes into a buffer and constructs a `Request` object
143    /// based on the received data. The request body is set using the received bytes.
144    ///
145    /// # Arguments
146    /// - `reader` - A mutable reference to a `BufReader` wrapping a `TcpStream`.
147    ///   This reader is used to read the incoming WebSocket request data.
148    /// - `buffer_size`: - Request buffer size.
149    /// - `request` - A reference to a `Request` object. This object is used as a template.
150    ///
151    /// # Returns
152    /// - `Ok(Request)` - A `Request` object constructed from the received data.
153    ///   - If no data is read (`Ok(0)`), an empty `Request` object is returned.
154    ///   - If data is successfully read, the request body is set with the received bytes.
155    /// - `Err(RequestError::InvalidWebSocketRequest)` - If an error occurs while reading from the stream.
156    pub async fn ws_from_reader(
157        reader: &mut BufReader<&mut TcpStream>,
158        buffer_size: usize,
159        request: &mut Self,
160    ) -> RequestReaderHandleResult {
161        let mut dynamic_buffer: Vec<u8> = Vec::with_capacity(buffer_size);
162        let mut temp_buffer: Vec<u8> = vec![0; buffer_size];
163        let mut full_frame: Vec<u8> = Vec::new();
164        let mut error_handle = || {
165            request.body.clear();
166        };
167        loop {
168            let len: usize = match reader.read(&mut temp_buffer).await {
169                Ok(len) => len,
170                Err(err) => {
171                    error_handle();
172                    if err.kind() == ErrorKind::ConnectionReset
173                        || err.kind() == ErrorKind::ConnectionAborted
174                    {
175                        return Err(RequestError::ClientDisconnected);
176                    }
177                    return Err(RequestError::InvalidWebSocketRequest(err.to_string()));
178                }
179            };
180            if len == 0 {
181                error_handle();
182                return Err(RequestError::IncompleteWebSocketFrame);
183            }
184            dynamic_buffer.extend_from_slice(&temp_buffer[..len]);
185            while let Some((frame, consumed)) = WebSocketFrame::decode_ws_frame(&dynamic_buffer) {
186                dynamic_buffer.drain(0..consumed);
187                match frame.get_opcode() {
188                    WebSocketOpcode::Close => {
189                        error_handle();
190                        return Err(RequestError::ClientClosedConnection);
191                    }
192                    WebSocketOpcode::Ping | WebSocketOpcode::Pong => {
193                        continue;
194                    }
195                    WebSocketOpcode::Text | WebSocketOpcode::Binary => {
196                        full_frame.extend_from_slice(frame.get_payload_data());
197                        if *frame.get_fin() {
198                            let mut request: Request = request.clone();
199                            request.body = full_frame;
200                            return Ok(request);
201                        }
202                    }
203                    _ => {
204                        error_handle();
205                        return Err(RequestError::InvalidWebSocketFrame(
206                            "Unsupported opcode".into(),
207                        ));
208                    }
209                }
210            }
211        }
212    }
213
214    /// Parse querys
215    ///
216    /// # Parameters
217    /// - `query`: &str
218    ///
219    /// # Returns
220    /// - RequestQuerys
221    fn parse_querys(query: &str) -> RequestQuerys {
222        let mut query_map: RequestQuerys = hash_map_xx_hash3_64();
223        for pair in query.split(AND) {
224            if let Some((key, value)) = pair.split_once(EQUAL) {
225                if !key.is_empty() {
226                    query_map.insert(key.to_string(), value.to_string());
227                }
228            } else if !pair.is_empty() {
229                query_map.insert(pair.to_string(), String::new());
230            }
231        }
232        query_map
233    }
234
235    /// Retrieves the value of a query parameter by its key.
236    ///
237    /// # Parameters
238    /// - `key`: The query parameter's key, which can be of any type that implements `Into<RequestQuerysKey>`.
239    ///
240    /// # Returns
241    /// - `OptionRequestQuerysValue`: Returns `Some(value)` if the key exists in the query parameters,
242    ///   or `None` if the key does not exist.
243    pub fn get_query<K>(&self, key: K) -> OptionRequestQuerysValue
244    where
245        K: Into<RequestQuerysKey>,
246    {
247        self.querys.get(&key.into()).cloned()
248    }
249
250    /// Retrieves the value of a request header by its key.
251    ///
252    /// # Parameters
253    /// - `key`: The header's key, which can be of any type that implements `Into<RequestHeadersKey>`.
254    ///
255    /// # Returns
256    /// - `OptionRequestHeadersValue`: Returns `Some(value)` if the key exists in the request headers,
257    ///   or `None` if the key does not exist.
258    pub fn get_header<K>(&self, key: K) -> OptionRequestHeadersValue
259    where
260        K: Into<RequestHeadersKey>,
261    {
262        self.headers.get(&key.into()).cloned()
263    }
264
265    /// Retrieves the first value of a request header by its key.
266    ///
267    /// # Parameters
268    /// - `key`: The header's key, which can be of any type that implements `Into<RequestHeadersKey>`.
269    ///
270    /// # Returns
271    /// - `OptionRequestHeadersValueItem`: Returns `Some(value)` if the key exists and has at least one value,
272    ///   or `None` if the key does not exist or has no values.
273    pub fn get_header_front<K>(&self, key: K) -> OptionRequestHeadersValueItem
274    where
275        K: Into<RequestHeadersKey>,
276    {
277        self.headers
278            .get(&key.into())
279            .and_then(|values| values.front().cloned())
280    }
281
282    /// Retrieves the last value of a request header by its key.
283    ///
284    /// # Parameters
285    /// - `key`: The header's key, which can be of any type that implements `Into<RequestHeadersKey>`.
286    ///
287    /// # Returns
288    /// - `OptionRequestHeadersValueItem`: Returns `Some(value)` if the key exists and has at least one value,
289    ///   or `None` if the key does not exist or has no values.
290    pub fn get_header_back<K>(&self, key: K) -> OptionRequestHeadersValueItem
291    where
292        K: Into<RequestHeadersKey>,
293    {
294        self.headers
295            .get(&key.into())
296            .and_then(|values| values.back().cloned())
297    }
298
299    /// Retrieves the number of values for a specific header.
300    ///
301    /// # Parameters
302    /// - `key`: The header's key, which can be of any type that implements `Into<RequestHeadersKey>`.
303    ///
304    /// # Returns
305    /// - `usize`: The number of values for the specified header. Returns 0 if the header does not exist.
306    pub fn get_header_len<K>(&self, key: K) -> usize
307    where
308        K: Into<RequestHeadersKey>,
309    {
310        self.headers
311            .get(&key.into())
312            .map(|values| values.len())
313            .unwrap_or(0)
314    }
315
316    /// Retrieves the total number of header values across all headers.
317    ///
318    /// # Returns
319    /// - `usize`: The total count of all header values.
320    pub fn get_headers_values_len(&self) -> usize {
321        self.headers.values().map(|values| values.len()).sum()
322    }
323
324    /// Retrieves the number of unique headers.
325    ///
326    /// # Returns
327    /// - `usize`: The number of unique header keys.
328    pub fn get_headers_len(&self) -> usize {
329        self.headers.len()
330    }
331
332    /// Checks if a specific header exists.
333    ///
334    /// # Parameters
335    /// - `key`: The header key to check, which will be converted into a `RequestHeadersKey`.
336    ///
337    /// # Returns
338    /// - `bool`: Returns `true` if the header exists, `false` otherwise.
339    pub fn has_header<K>(&self, key: K) -> bool
340    where
341        K: Into<RequestHeadersKey>,
342    {
343        self.headers.contains_key(&key.into())
344    }
345
346    /// Checks if a header contains a specific value.
347    ///
348    /// # Parameters
349    /// - `key`: The header key to check, which will be converted into a `RequestHeadersKey`.
350    /// - `value`: The value to search for in the header.
351    ///
352    /// # Returns
353    /// - `bool`: Returns `true` if the header exists and contains the specified value, `false` otherwise.
354    pub fn has_header_value<K, V>(&self, key: K, value: V) -> bool
355    where
356        K: Into<RequestHeadersKey>,
357        V: Into<RequestHeadersValueItem>,
358    {
359        let key: RequestHeadersKey = key.into();
360        let value: RequestHeadersValueItem = value.into();
361        if let Some(values) = self.headers.get(&key) {
362            values.contains(&value)
363        } else {
364            false
365        }
366    }
367
368    /// Retrieves the body content of the object as a UTF-8 encoded string.
369    ///
370    /// This method uses `String::from_utf8_lossy` to convert the byte slice returned by `self.get_body()` into a string.
371    /// If the byte slice contains invalid UTF-8 sequences, they will be replaced with the Unicode replacement character (�).
372    ///
373    /// # Returns
374    /// A `String` containing the body content.
375    pub fn get_body_string(&self) -> String {
376        String::from_utf8_lossy(self.get_body()).into_owned()
377    }
378
379    /// Deserializes the body content of the object into a specified type `T`.
380    ///
381    /// This method first retrieves the body content as a UTF-8 encoded string using `self.get_body()`.
382    /// It then attempts to deserialize the string into the specified type `T` using `json_from_slice`.
383    ///
384    /// # Type Parameters
385    /// - `T`: The target type to deserialize into. It must implement the `DeserializeOwned` trait.
386    ///
387    /// # Returns
388    /// - `Ok(T)`: The deserialized object of type `T` if the deserialization is successful.
389    /// - `Err(ResultJsonError)`: An error if the deserialization fails (e.g., invalid JSON format or type mismatch).
390    pub fn get_body_json<T>(&self) -> ResultJsonError<T>
391    where
392        T: DeserializeOwned,
393    {
394        json_from_slice(self.get_body())
395    }
396
397    /// Converts the request to a formatted string representation.
398    ///
399    /// - Returns: A `String` containing formatted request details.
400    pub fn get_string(&self) -> String {
401        let body: &Vec<u8> = self.get_body();
402        let body_type: &'static str = if std::str::from_utf8(body).is_ok() {
403            PLAIN
404        } else {
405            BINARY
406        };
407        format!(
408            "[Request] => [method]: {}; [host]: {}; [version]: {}; [path]: {}; [querys]: {:?}; [headers]: {:?}; [body]: {} bytes {};",
409            self.get_method(),
410            self.get_host(),
411            self.get_version(),
412            self.get_path(),
413            self.get_querys(),
414            self.get_headers(),
415            body.len(),
416            body_type
417        )
418    }
419
420    /// Retrieves the upgrade type from the request headers.
421    ///
422    /// - Returns: The `UpgradeType` extracted from the `UPGRADE` header.
423    ///            If the header is missing or invalid, returns the default `UpgradeType`.
424    pub fn get_upgrade_type(&self) -> UpgradeType {
425        let upgrade_type: UpgradeType = self
426            .get_header_back(UPGRADE)
427            .and_then(|data| data.parse::<UpgradeType>().ok())
428            .unwrap_or_default();
429        upgrade_type
430    }
431
432    /// Checks whether the WebSocket upgrade is enabled.
433    ///
434    /// - Returns: `true` if the upgrade type is WebSocket; otherwise, `false`.
435    pub fn is_ws(&self) -> bool {
436        self.get_upgrade_type().is_ws()
437    }
438
439    /// Checks if the current upgrade type is HTTP/2 cleartext (h2c).
440    ///
441    /// - `&self` - The current instance (usually a request or context struct).
442    ///
443    /// - Returns `true` if the upgrade type is `h2c`, otherwise `false`.
444    pub fn is_h2c(&self) -> bool {
445        self.get_upgrade_type().is_h2c()
446    }
447
448    /// Checks if the current upgrade type is TLS (any version).
449    ///
450    /// - `&self` - The current instance (usually a request or context struct).
451    ///
452    /// - Returns `true` if the upgrade type is any `Tls` variant, otherwise `false`.
453    pub fn is_tls(&self) -> bool {
454        self.get_upgrade_type().is_tls()
455    }
456
457    /// Checks whether the upgrade type is unknown.
458    ///
459    /// - Returns: `true` if the upgrade type is unknown; otherwise, `false`.
460    pub fn is_unknown_upgrade(&self) -> bool {
461        self.get_upgrade_type().is_unknown()
462    }
463
464    /// Checks if the HTTP version is HTTP/1.1 or higher.
465    ///
466    /// - Returns: `true` if the HTTP version is 1.1 or higher; otherwise, `false`.
467    pub fn is_http1_1_or_higher(&self) -> bool {
468        self.get_version().is_http1_1_or_higher()
469    }
470
471    /// Checks whether the HTTP version is HTTP/0.9.
472    ///
473    /// - Returns: `true` if the version is HTTP/0.9; otherwise, `false`.
474    pub fn is_http0_9(&self) -> bool {
475        self.get_version().is_http0_9()
476    }
477
478    /// Checks whether the HTTP version is HTTP/1.0.
479    ///
480    /// - Returns: `true` if the version is HTTP/1.0; otherwise, `false`.
481    pub fn is_http1_0(&self) -> bool {
482        self.get_version().is_http1_0()
483    }
484
485    /// Checks whether the HTTP version is HTTP/1.1.
486    ///
487    /// - Returns: `true` if the version is HTTP/1.1; otherwise, `false`.
488    pub fn is_http1_1(&self) -> bool {
489        self.get_version().is_http1_1()
490    }
491
492    /// Checks whether the HTTP version is HTTP/2.
493    ///
494    /// - Returns: `true` if the version is HTTP/2; otherwise, `false`.
495    pub fn is_http2(&self) -> bool {
496        self.get_version().is_http2()
497    }
498
499    /// Checks whether the HTTP version is HTTP/3.
500    ///
501    /// - Returns: `true` if the version is HTTP/3; otherwise, `false`.
502    pub fn is_http3(&self) -> bool {
503        self.get_version().is_http3()
504    }
505
506    /// Checks whether the HTTP version is unknown.
507    ///
508    /// - Returns: `true` if the version is unknown; otherwise, `false`.
509    pub fn is_unknown_version(&self) -> bool {
510        self.get_version().is_unknown()
511    }
512
513    /// Checks whether the version belongs to the HTTP family.
514    ///
515    /// - Returns: `true` if the version is a valid HTTP version; otherwise, `false`.
516    pub fn is_http(&self) -> bool {
517        self.get_version().is_http()
518    }
519
520    /// Checks whether the request method is `GET`.
521    ///
522    /// - Returns: `true` if the method is `GET`; otherwise, `false`.
523    pub fn is_get(&self) -> bool {
524        self.get_method().is_get()
525    }
526
527    /// Checks whether the request method is `POST`.
528    ///
529    /// - Returns: `true` if the method is `POST`; otherwise, `false`.
530    pub fn is_post(&self) -> bool {
531        self.get_method().is_post()
532    }
533
534    /// Checks whether the request method is `PUT`.
535    ///
536    /// - Returns: `true` if the method is `PUT`; otherwise, `false`.
537    pub fn is_put(&self) -> bool {
538        self.get_method().is_put()
539    }
540
541    /// Checks whether the request method is `DELETE`.
542    ///
543    /// - Returns: `true` if the method is `DELETE`; otherwise, `false`.
544    pub fn is_delete(&self) -> bool {
545        self.get_method().is_delete()
546    }
547
548    /// Checks whether the request method is `PATCH`.
549    ///
550    /// - Returns: `true` if the method is `PATCH`; otherwise, `false`.
551    pub fn is_patch(&self) -> bool {
552        self.get_method().is_patch()
553    }
554
555    /// Checks whether the request method is `HEAD`.
556    ///
557    /// - Returns: `true` if the method is `HEAD`; otherwise, `false`.
558    pub fn is_head(&self) -> bool {
559        self.get_method().is_head()
560    }
561
562    /// Checks whether the request method is `OPTIONS`.
563    ///
564    /// - Returns: `true` if the method is `OPTIONS`; otherwise, `false`.
565    pub fn is_options(&self) -> bool {
566        self.get_method().is_options()
567    }
568
569    /// Checks whether the request method is `CONNECT`.
570    ///
571    /// - Returns: `true` if the method is `CONNECT`; otherwise, `false`.
572    pub fn is_connect(&self) -> bool {
573        self.get_method().is_connect()
574    }
575
576    /// Checks whether the request method is `TRACE`.
577    ///
578    /// - Returns: `true` if the method is `TRACE`; otherwise, `false`.
579    pub fn is_trace(&self) -> bool {
580        self.get_method().is_trace()
581    }
582
583    /// Checks whether the request method is `UNKNOWN`.
584    ///
585    /// - Returns: `true` if the method is `UNKNOWN`; otherwise, `false`.
586    pub fn is_unknown_method(&self) -> bool {
587        self.get_method().is_unknown()
588    }
589
590    /// Determines if keep-alive connection should be enabled for this request.
591    ///
592    /// This function checks the Connection header and HTTP version to determine if
593    /// keep-alive should be enabled. The logic is as follows:
594    ///
595    /// 1. If Connection header exists:
596    ///    - Returns true if header value is "keep-alive"
597    ///    - Returns false if header value is "close"
598    /// 2. If no Connection header:
599    ///    - Returns true if HTTP version is 1.1 or higher
600    ///    - Returns false otherwise
601    ///
602    /// # Returns
603    /// - `bool`: true if keep-alive should be enabled, false otherwise
604    pub fn is_enable_keep_alive(&self) -> bool {
605        if let Some(connection_value) = self.get_header_back(CONNECTION) {
606            if connection_value.eq_ignore_ascii_case(KEEP_ALIVE) {
607                return true;
608            } else if connection_value.eq_ignore_ascii_case(CLOSE) {
609                return self.is_ws();
610            }
611        }
612        self.is_http1_1_or_higher() || self.is_ws()
613    }
614}