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}