Skip to main content

http_type/request/
impl.rs

1use crate::*;
2
3/// Implements the `std::error::Error` trait for `RequestError`.
4impl std::error::Error for RequestError {}
5
6/// Provides a default value for `RequestError`.
7impl Default for RequestError {
8    /// Provides a default value for `RequestError`.
9    ///
10    /// Returns a `RequestError::Unknown` with `HttpStatus::InternalServerError`.
11    #[inline(always)]
12    fn default() -> Self {
13        RequestError::Unknown(HttpStatus::InternalServerError)
14    }
15}
16
17/// Converts an I/O error to a `RequestError`.
18///
19/// Maps connection reset and aborted errors to `ClientDisconnected`,
20/// all other I/O errors are mapped to `ReadConnection`.
21impl From<std::io::Error> for RequestError {
22    /// Converts an I/O error to a `RequestError`.
23    ///
24    /// # Arguments
25    ///
26    /// - `std::io::Error`: The I/O error to convert.
27    ///
28    /// # Returns
29    ///
30    /// - `RequestError`: The corresponding request error.
31    #[inline(always)]
32    fn from(error: std::io::Error) -> Self {
33        let kind: ErrorKind = error.kind();
34        if kind == ErrorKind::ConnectionReset || kind == ErrorKind::ConnectionAborted {
35            return RequestError::ClientDisconnected(HttpStatus::BadRequest);
36        }
37        RequestError::ReadConnection(HttpStatus::BadRequest)
38    }
39}
40
41/// Converts a timeout elapsed error to a `RequestError`.
42///
43/// Maps timeout errors to `ReadTimeout` with `HttpStatus::RequestTimeout`.
44impl From<Elapsed> for RequestError {
45    /// Converts a timeout elapsed error to a `RequestError`.
46    ///
47    /// # Arguments
48    ///
49    /// - `Elapsed`: The elapsed error to convert.
50    ///
51    /// # Returns
52    ///
53    /// - `RequestError`: The corresponding request error as `ReadTimeout`.
54    #[inline(always)]
55    fn from(_: Elapsed) -> Self {
56        RequestError::ReadTimeout(HttpStatus::RequestTimeout)
57    }
58}
59
60/// Converts a parse int error to a `RequestError`.
61///
62/// Maps parse int errors to `InvalidContentLength` with `HttpStatus::BadRequest`.
63impl From<ParseIntError> for RequestError {
64    /// Converts a parse int error to a `RequestError`.
65    ///
66    /// # Arguments
67    ///
68    /// - `ParseIntError`: The parse error to convert.
69    ///
70    /// # Returns
71    ///
72    /// - `RequestError`: The corresponding request error as `InvalidContentLength`.
73    #[inline(always)]
74    fn from(_: ParseIntError) -> Self {
75        RequestError::InvalidContentLength(HttpStatus::BadRequest)
76    }
77}
78
79/// Converts a response error to a `RequestError`.
80///
81/// Maps response errors to `WriteTimeout` with `HttpStatus::InternalServerError`.
82impl From<ResponseError> for RequestError {
83    /// Converts a response error to a `RequestError`.
84    ///
85    /// # Arguments
86    ///
87    /// - `ResponseError`: The response error to convert.
88    ///
89    /// # Returns
90    ///
91    /// - `RequestError`: The corresponding request error as `WriteTimeout`.
92    #[inline(always)]
93    fn from(_: ResponseError) -> Self {
94        RequestError::WriteTimeout(HttpStatus::InternalServerError)
95    }
96}
97
98impl RequestError {
99    /// Gets the HTTP status associated with this error.
100    ///
101    /// Returns the HttpStatus enum variant that corresponds to this error.
102    ///
103    /// # Returns
104    ///
105    /// - `HttpStatus` - The HTTP status associated with this error.
106    pub fn get_http_status(&self) -> HttpStatus {
107        match self {
108            Self::HttpRead(status) => *status,
109            Self::GetTcpStream(status) => *status,
110            Self::GetTlsStream(status) => *status,
111            Self::ReadConnection(status) => *status,
112            Self::RequestAborted(status) => *status,
113            Self::TlsStreamConnect(status) => *status,
114            Self::NeedOpenRedirect(status) => *status,
115            Self::MaxRedirectTimes(status) => *status,
116            Self::MethodsNotSupport(status) => *status,
117            Self::RedirectInvalidUrl(status) => *status,
118            Self::ClientDisconnected(status) => *status,
119            Self::RedirectUrlDeadLoop(status) => *status,
120            Self::ClientClosedConnection(status) => *status,
121            Self::IncompleteWebSocketFrame(status) => *status,
122            Self::RequestTooLong(status) => *status,
123            Self::PathTooLong(status) => *status,
124            Self::QueryTooLong(status) => *status,
125            Self::HeaderLineTooLong(status) => *status,
126            Self::TooManyHeaders(status) => *status,
127            Self::HeaderKeyTooLong(status) => *status,
128            Self::HeaderValueTooLong(status) => *status,
129            Self::ContentLengthTooLarge(status) => *status,
130            Self::InvalidContentLength(status) => *status,
131            Self::InvalidUrlScheme(status) => *status,
132            Self::InvalidUrlHost(status) => *status,
133            Self::InvalidUrlPort(status) => *status,
134            Self::InvalidUrlPath(status) => *status,
135            Self::InvalidUrlQuery(status) => *status,
136            Self::InvalidUrlFragment(status) => *status,
137            Self::ReadTimeout(status) => *status,
138            Self::WriteTimeout(status) => *status,
139            Self::TcpConnectionFailed(status) => *status,
140            Self::TlsHandshakeFailed(status) => *status,
141            Self::TlsCertificateInvalid(status) => *status,
142            Self::WebSocketFrameTooLarge(status) => *status,
143            Self::WebSocketOpcodeUnsupported(status) => *status,
144            Self::WebSocketMaskMissing(status) => *status,
145            Self::WebSocketPayloadCorrupted(status) => *status,
146            Self::WebSocketInvalidUtf8(status) => *status,
147            Self::WebSocketInvalidCloseCode(status) => *status,
148            Self::WebSocketInvalidExtension(status) => *status,
149            Self::HttpRequestPartsInsufficient(status) => *status,
150            Self::TcpStreamConnect(status) => *status,
151            Self::TlsConnectorBuild(status) => *status,
152            Self::InvalidUrl(status) => *status,
153            Self::ConfigReadError(status) => *status,
154            Self::TcpStreamConnectString(status) => *status,
155            Self::TlsConnectorBuildString(status) => *status,
156            Self::Request(_) => HttpStatus::BadRequest,
157            Self::NotFoundStream(status) => *status,
158            Self::Unknown(status) => *status,
159        }
160    }
161
162    /// Gets the numeric HTTP status code associated with this error.
163    ///
164    /// Returns the numeric status code (e.g., 400, 404, 500) that corresponds to this error.
165    ///
166    /// # Returns
167    ///
168    /// - `ResponseStatusCode` - The numeric HTTP status code.
169    pub fn get_http_status_code(&self) -> ResponseStatusCode {
170        self.get_http_status().code()
171    }
172}
173
174/// Implementation of `Default` trait for `RequestConfig`.
175impl Default for RequestConfig {
176    /// Creates a new `RequestConfig` with default secure settings.
177    ///
178    /// This constructor initializes the configuration with standard security limits
179    /// suitable for most HTTP request parsing scenarios.
180    ///
181    /// # Returns
182    ///
183    /// - `Self` - A new `RequestConfig` instance with default settings.
184    #[inline(always)]
185    fn default() -> Self {
186        Self {
187            buffer_size: DEFAULT_BUFFER_SIZE,
188            max_path_size: DEFAULT_MAX_PATH_SIZE,
189            max_header_count: DEFAULT_MAX_HEADER_COUNT,
190            max_header_key_size: DEFAULT_MAX_HEADER_KEY_SIZE,
191            max_header_value_size: DEFAULT_MAX_HEADER_VALUE_SIZE,
192            max_body_size: DEFAULT_MAX_BODY_SIZE,
193            read_timeout_ms: DEFAULT_READ_TIMEOUT_MS,
194        }
195    }
196}
197
198impl RequestConfig {
199    /// Creates a new `RequestConfig` from a JSON string.
200    ///
201    /// # Arguments
202    ///
203    /// - `AsRef<str>` - The configuration.
204    ///
205    /// # Returns
206    ///
207    /// - `Result<RequestConfig, serde_json::Error>` - The parsed `RequestConfig` or an error.
208    pub fn from_json<C>(json: C) -> Result<RequestConfig, serde_json::Error>
209    where
210        C: AsRef<str>,
211    {
212        serde_json::from_str(json.as_ref())
213    }
214
215    /// Creates a new `RequestConfig` with low-security settings.
216    ///
217    /// This constructor initializes the configuration with less restrictive limits
218    /// for environments where higher limits are needed.
219    ///
220    /// # Returns
221    ///
222    /// - `Self` - A new `RequestConfig` instance with low-security settings.
223    #[inline(always)]
224    pub fn low_security() -> Self {
225        Self {
226            buffer_size: DEFAULT_LOW_SECURITY_BUFFER_SIZE,
227            max_path_size: DEFAULT_LOW_SECURITY_MAX_PATH_SIZE,
228            max_header_count: DEFAULT_LOW_SECURITY_MAX_HEADER_COUNT,
229            max_header_key_size: DEFAULT_LOW_SECURITY_MAX_HEADER_KEY_SIZE,
230            max_header_value_size: DEFAULT_LOW_SECURITY_MAX_HEADER_VALUE_SIZE,
231            max_body_size: DEFAULT_LOW_SECURITY_MAX_BODY_SIZE,
232            read_timeout_ms: DEFAULT_LOW_SECURITY_READ_TIMEOUT_MS,
233        }
234    }
235
236    /// Creates a new `RequestConfig` with high-security settings.
237    ///
238    /// This constructor initializes the configuration with more restrictive limits
239    /// to provide maximum protection against various attacks in high-risk environments.
240    ///
241    /// # Returns
242    ///
243    /// - `Self` - A new `RequestConfig` instance with high-security settings.
244    #[inline(always)]
245    pub fn high_security() -> Self {
246        Self {
247            buffer_size: DEFAULT_HIGH_SECURITY_BUFFER_SIZE,
248            max_path_size: DEFAULT_HIGH_SECURITY_MAX_PATH_SIZE,
249            max_header_count: DEFAULT_HIGH_SECURITY_MAX_HEADER_COUNT,
250            max_header_key_size: DEFAULT_HIGH_SECURITY_MAX_HEADER_KEY_SIZE,
251            max_header_value_size: DEFAULT_HIGH_SECURITY_MAX_HEADER_VALUE_SIZE,
252            max_body_size: DEFAULT_HIGH_SECURITY_MAX_BODY_SIZE,
253            read_timeout_ms: DEFAULT_HIGH_SECURITY_READ_TIMEOUT_MS,
254        }
255    }
256}
257
258/// Provides a default value for `Request`.
259///
260/// Returns a new `Request` instance with all fields initialized to their default values.
261impl Default for Request {
262    #[inline(always)]
263    fn default() -> Self {
264        Self {
265            method: Method::default(),
266            host: String::new(),
267            version: HttpVersion::default(),
268            path: String::new(),
269            querys: hash_map_xx_hash3_64(),
270            headers: hash_map_xx_hash3_64(),
271            body: Vec::new(),
272        }
273    }
274}
275
276impl Request {
277    /// Parses the first line of HTTP request into method, path, and version components.
278    ///
279    /// # Arguments
280    ///
281    /// - `&str`: The first line string of HTTP request to parse.
282    ///
283    /// # Returns
284    ///
285    /// - `Result<(RequestMethod, &str, RequestVersion), RequestError>`: A tuple containing:
286    ///   - The parsed HTTP method
287    ///   - The full path string
288    ///   - The parsed HTTP version
289    ///   - Or an error if parsing fails
290    #[inline(always)]
291    pub(crate) fn get_http_first_line(
292        line: &str,
293    ) -> Result<(RequestMethod, &str, RequestVersion), RequestError> {
294        let mut parts: SplitWhitespace<'_> = line.split_whitespace();
295        let method_str: &str = parts
296            .next()
297            .ok_or(RequestError::HttpRequestPartsInsufficient(
298                HttpStatus::BadRequest,
299            ))?;
300        let full_path: &str = parts
301            .next()
302            .ok_or(RequestError::HttpRequestPartsInsufficient(
303                HttpStatus::BadRequest,
304            ))?;
305        let version_str: &str = parts
306            .next()
307            .ok_or(RequestError::HttpRequestPartsInsufficient(
308                HttpStatus::BadRequest,
309            ))?;
310        let method: RequestMethod = method_str
311            .parse::<RequestMethod>()
312            .unwrap_or_else(|_| Method::Unknown(method_str.to_string()));
313        let version: RequestVersion = version_str
314            .parse::<RequestVersion>()
315            .unwrap_or_else(|_| RequestVersion::Unknown(version_str.to_string()));
316        Ok((method, full_path, version))
317    }
318
319    /// Validates the path length against the maximum allowed size.
320    ///
321    /// # Arguments
322    ///
323    /// - `&str`: The path string to check.
324    /// - `usize`: The maximum allowed path size.
325    ///
326    /// # Returns
327    ///
328    /// - `Result<(), RequestError>`: Ok if valid, or an error if the path is too long.
329    #[inline(always)]
330    pub(crate) fn check_http_path_size(path: &str, max_size: usize) -> Result<(), RequestError> {
331        if path.len() > max_size && max_size != DEFAULT_LOW_SECURITY_MAX_PATH_SIZE {
332            return Err(RequestError::PathTooLong(HttpStatus::URITooLong));
333        }
334        Ok(())
335    }
336
337    /// Parses the query string from the full path.
338    ///
339    /// Handles both query parameters (after `?`) and hash fragments (after `#`),
340    /// ensuring proper parsing when both are present.
341    ///
342    /// # Arguments
343    ///
344    /// - `&str`: The full path string containing the query.
345    /// - `Option<usize>`: The index of the query separator (`?`), if present.
346    /// - `Option<usize>`: The index of the hash separator (`#`), if present.
347    ///
348    /// # Returns
349    ///
350    /// - `&str`: The parsed query string slice, or empty string if no query.
351    #[inline(always)]
352    pub(crate) fn get_http_query(
353        path: &str,
354        query_index: Option<usize>,
355        hash_index: Option<usize>,
356    ) -> &str {
357        query_index.map_or(EMPTY_STR, |i: usize| {
358            let temp: &str = &path[i + 1..];
359            match hash_index {
360                None => temp,
361                Some(hash_idx) if hash_idx <= i => temp,
362                Some(hash_idx) => &temp[..hash_idx - i - 1],
363            }
364        })
365    }
366
367    /// Parses the request path without query string or hash fragment.
368    ///
369    /// # Arguments
370    ///
371    /// - `&str`: The full path string.
372    /// - `Option<usize>`: The index of the query separator (`?`), if present.
373    /// - `Option<usize>`: The index of the hash separator (`#`), if present.
374    ///
375    /// # Returns
376    ///
377    /// - `RequestPath`: The request path without query or hash.
378    #[inline(always)]
379    pub(crate) fn get_http_path(
380        path: &str,
381        query_index: Option<usize>,
382        hash_index: Option<usize>,
383    ) -> RequestPath {
384        match query_index.or(hash_index) {
385            Some(i) => path[..i].to_owned(),
386            None => path.to_owned(),
387        }
388    }
389
390    /// Parses a query string as_ref key-value pairs.
391    ///
392    /// Expects format "key1=value1&key2=value2". Empty values are allowed.
393    ///
394    /// # Arguments
395    ///
396    /// - `&str` - The query string to parse.
397    ///
398    /// # Returns
399    ///
400    /// - `RequestQuerys` - The parsed query parameters.
401    #[inline(always)]
402    pub(crate) fn get_http_querys(query: &str) -> RequestQuerys {
403        let estimated_capacity: usize = query.matches(AND).count() + 1;
404        let mut query_map: RequestQuerys = HashMapXxHash3_64::with_capacity_and_hasher(
405            estimated_capacity,
406            BuildHasherDefault::default(),
407        );
408        for pair in query.split(AND) {
409            if let Some((key, value)) = pair.split_once(EQUAL) {
410                if !key.is_empty() {
411                    query_map.insert(key.to_string(), value.to_string());
412                }
413            } else if !pair.is_empty() {
414                query_map.insert(pair.to_string(), String::new());
415            }
416        }
417        query_map
418    }
419
420    /// Checks if the header count exceeds the maximum allowed.
421    ///
422    /// # Arguments
423    ///
424    /// - `usize`: The current number of headers parsed.
425    /// - `usize`: The maximum allowed number of headers.
426    ///
427    /// # Returns
428    ///
429    /// - `Result<(), RequestError>`: Returns an error if the limit is exceeded and not in low security mode.
430    #[inline(always)]
431    pub(crate) fn check_http_header_count(
432        count: usize,
433        max_count: usize,
434    ) -> Result<(), RequestError> {
435        if count > max_count && max_count != DEFAULT_LOW_SECURITY_MAX_HEADER_COUNT {
436            return Err(RequestError::TooManyHeaders(
437                HttpStatus::RequestHeaderFieldsTooLarge,
438            ));
439        }
440        Ok(())
441    }
442
443    /// Checks if a header key exceeds the maximum allowed length.
444    ///
445    /// # Arguments
446    ///
447    /// - `&str`: The header key to check.
448    /// - `usize`: The maximum allowed length for a header key.
449    ///
450    /// # Returns
451    ///
452    /// - `Result<(), RequestError>`: Returns an error if the limit is exceeded and not in low security mode.
453    #[inline(always)]
454    pub(crate) fn check_http_header_key_size(
455        key: &str,
456        max_size: usize,
457    ) -> Result<(), RequestError> {
458        if key.len() > max_size && max_size != DEFAULT_LOW_SECURITY_MAX_HEADER_KEY_SIZE {
459            return Err(RequestError::HeaderKeyTooLong(
460                HttpStatus::RequestHeaderFieldsTooLarge,
461            ));
462        }
463        Ok(())
464    }
465
466    /// Checks if a header value exceeds the maximum allowed length.
467    ///
468    /// # Arguments
469    ///
470    /// - `&str`: The header value to check.
471    /// - `usize`: The maximum allowed length for a header value.
472    ///
473    /// # Returns
474    ///
475    /// - `Result<(), RequestError>`: Returns an error if the limit is exceeded and not in low security mode.
476    #[inline(always)]
477    pub(crate) fn check_http_header_value_size(
478        value: &str,
479        max_size: usize,
480    ) -> Result<(), RequestError> {
481        if value.len() > max_size && max_size != DEFAULT_LOW_SECURITY_MAX_HEADER_VALUE_SIZE {
482            return Err(RequestError::HeaderValueTooLong(
483                HttpStatus::RequestHeaderFieldsTooLarge,
484            ));
485        }
486        Ok(())
487    }
488
489    /// Parses the Content-Length header value and checks it against max body size.
490    ///
491    /// # Arguments
492    ///
493    /// - `&str`: The Content-Length header value string.
494    /// - `usize`: The maximum allowed body size.
495    ///
496    /// # Returns
497    ///
498    /// - `Result<usize, RequestError>`: The parsed content length or an error.
499    #[inline(always)]
500    pub(crate) fn check_http_body_size(
501        value: &str,
502        max_size: usize,
503    ) -> Result<usize, RequestError> {
504        let length: usize = value.parse::<usize>()?;
505        if length > max_size && max_size != DEFAULT_LOW_SECURITY_MAX_BODY_SIZE {
506            return Err(RequestError::ContentLengthTooLarge(
507                HttpStatus::PayloadTooLarge,
508            ));
509        }
510        Ok(length)
511    }
512
513    /// Parses HTTP headers from a buffered reader.
514    ///
515    /// This method reads header lines from the provided buffered reader until an empty line
516    /// is encountered, which indicates the end of headers. It checks header count, length,
517    /// and content according to the provided configuration.
518    ///
519    /// # Arguments
520    ///
521    /// - `&mut AsyncBufReadExt + Unpin`: A mutable reference to a buffered reader implementing `AsyncBufReadExt`.
522    /// - `&RequestConfig`: Configuration for security limits and buffer settings.
523    ///
524    /// # Returns
525    ///
526    /// - `Result<(RequestHeaders, RequestHost, usize), RequestError>`: A tuple containing:
527    ///   - The parsed headers as a hash map
528    ///   - The host value parsed from the Host header
529    ///   - The content length parsed from the Content-Length header
530    ///   - Or an error if parsing fails
531    pub(crate) async fn get_http_headers<R>(
532        reader: &mut R,
533        config: &RequestConfig,
534    ) -> Result<(RequestHeaders, RequestHost, usize), RequestError>
535    where
536        R: AsyncBufReadExt + Unpin,
537    {
538        let buffer_size: usize = config.get_buffer_size();
539        let max_header_count: usize = config.get_max_header_count();
540        let max_header_key_size: usize = config.get_max_header_key_size();
541        let max_header_value_size: usize = config.get_max_header_value_size();
542        let max_body_size: usize = config.get_max_body_size();
543        let mut headers: RequestHeaders =
544            HashMapXxHash3_64::with_capacity_and_hasher(B_16, BuildHasherDefault::default());
545        let mut host: RequestHost = String::new();
546        let mut content_size: usize = 0;
547        let mut header_count: usize = 0;
548        let mut header_line_buffer: String = String::with_capacity(buffer_size);
549        loop {
550            header_line_buffer.clear();
551            AsyncBufReadExt::read_line(reader, &mut header_line_buffer).await?;
552            let header_line: &str = header_line_buffer.trim();
553            if header_line.is_empty() {
554                break;
555            }
556            header_count += 1;
557            Self::check_http_header_count(header_count, max_header_count)?;
558            let (key_part, value_part): (&str, &str) = match header_line.split_once(COLON) {
559                Some(parts) => parts,
560                None => continue,
561            };
562            let key_trimmed: &str = key_part.trim();
563            if key_trimmed.is_empty() {
564                continue;
565            }
566            let key: String = key_trimmed.to_ascii_lowercase();
567            Self::check_http_header_key_size(&key, max_header_key_size)?;
568            let value: String = value_part.trim().to_string();
569            Self::check_http_header_value_size(&value, max_header_value_size)?;
570            match key.as_str() {
571                HOST => host = value.clone(),
572                CONTENT_LENGTH => {
573                    content_size = Self::check_http_body_size(&value, max_body_size)?;
574                }
575                _ => {}
576            }
577            headers.entry(key).or_default().push_back(value);
578        }
579        Ok((headers, host, content_size))
580    }
581
582    /// Reads the request body from the buffered reader.
583    ///
584    /// # Arguments
585    ///
586    /// - `&mut BufReader<&mut TcpStream>`: The buffered reader to read from.
587    /// - `usize`: The expected content size.
588    ///
589    /// # Returns
590    ///
591    /// - `Result<RequestBody, RequestError>`: The body bytes or an error.
592    #[inline(always)]
593    pub(crate) async fn get_http_body(
594        reader: &mut BufReader<&mut TcpStream>,
595        content_size: usize,
596    ) -> Result<RequestBody, RequestError> {
597        let mut body: RequestBody = Vec::with_capacity(content_size);
598        if content_size > 0 {
599            body.resize(content_size, 0);
600            AsyncReadExt::read_exact(reader, &mut body).await?;
601        }
602        Ok(body)
603    }
604
605    /// Tries to get a query parameter value by key.
606    ///
607    /// The key type must implement AsRef<str> conversion.
608    ///
609    /// # Arguments
610    ///
611    /// - `AsRef<str>` - The query parameter key (implements AsRef<str>).
612    ///
613    /// # Returns
614    ///
615    /// - `Option<RequestQuerysValue>` - The parameter value if exists.
616    #[inline(always)]
617    pub fn try_get_query<K>(&self, key: K) -> Option<RequestQuerysValue>
618    where
619        K: AsRef<str>,
620    {
621        self.querys.get(key.as_ref()).cloned()
622    }
623
624    /// Gets a query parameter value by key.
625    ///
626    /// The key type must implement AsRef<str> conversion.
627    ///
628    /// # Arguments
629    ///
630    /// - `AsRef<str>` - The query parameter key (implements AsRef<str>).
631    ///
632    /// # Returns
633    ///
634    /// - `RequestQuerysValue` - The parameter value if exists.
635    ///
636    /// # Panics
637    ///
638    /// This function will panic if the query parameter key is not found.
639    #[inline(always)]
640    pub fn get_query<K>(&self, key: K) -> RequestQuerysValue
641    where
642        K: AsRef<str>,
643    {
644        self.try_get_query(key).unwrap()
645    }
646
647    /// Tries to retrieve the value of a request header by its key.
648    ///
649    /// # Arguments
650    ///
651    /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
652    ///
653    /// # Returns
654    ///
655    /// - `Option<RequestHeadersValue>` - The optional header values.
656    #[inline(always)]
657    pub fn try_get_header<K>(&self, key: K) -> Option<RequestHeadersValue>
658    where
659        K: AsRef<str>,
660    {
661        self.headers.get(key.as_ref()).cloned()
662    }
663
664    /// Retrieves the value of a request header by its key.
665    ///
666    /// # Arguments
667    ///
668    /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
669    ///
670    /// # Returns
671    ///
672    /// - `RequestHeadersValue` - The optional header values.
673    ///
674    /// # Panics
675    ///
676    /// This function will panic if the header key is not found.
677    #[inline(always)]
678    pub fn get_header<K>(&self, key: K) -> RequestHeadersValue
679    where
680        K: AsRef<str>,
681    {
682        self.try_get_header(key).unwrap()
683    }
684
685    /// Tries to retrieve the first value of a request header by its key.
686    ///
687    /// # Arguments
688    ///
689    /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
690    ///
691    /// # Returns
692    ///
693    /// - `Option<RequestHeadersValueItem>` - The first header value if exists.
694    #[inline(always)]
695    pub fn try_get_header_front<K>(&self, key: K) -> Option<RequestHeadersValueItem>
696    where
697        K: AsRef<str>,
698    {
699        self.headers
700            .get(key.as_ref())
701            .and_then(|values| values.front().cloned())
702    }
703
704    /// Retrieves the first value of a request header by its key.
705    ///
706    /// # Arguments
707    ///
708    /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
709    ///
710    /// # Returns
711    ///
712    /// - `RequestHeadersValueItem` - The first header value if exists.
713    ///
714    /// # Panics
715    ///
716    /// This function will panic if the header key is not found.
717    #[inline(always)]
718    pub fn get_header_front<K>(&self, key: K) -> RequestHeadersValueItem
719    where
720        K: AsRef<str>,
721    {
722        self.try_get_header_front(key).unwrap()
723    }
724
725    /// Tries to retrieve the last value of a request header by its key.
726    ///
727    /// # Arguments
728    ///
729    /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
730    ///
731    /// # Returns
732    ///
733    /// - `Option<RequestHeadersValueItem>` - The last header value if exists.
734    #[inline(always)]
735    pub fn try_get_header_back<K>(&self, key: K) -> Option<RequestHeadersValueItem>
736    where
737        K: AsRef<str>,
738    {
739        self.headers
740            .get(key.as_ref())
741            .and_then(|values| values.back().cloned())
742    }
743
744    /// Retrieves the last value of a request header by its key.
745    ///
746    /// # Arguments
747    ///
748    /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
749    ///
750    /// # Returns
751    ///
752    /// - `RequestHeadersValueItem` - The last header value if exists.
753    ///
754    /// # Panics
755    ///
756    /// This function will panic if the header key is not found.
757    #[inline(always)]
758    pub fn get_header_back<K>(&self, key: K) -> RequestHeadersValueItem
759    where
760        K: AsRef<str>,
761    {
762        self.try_get_header_back(key).unwrap()
763    }
764
765    /// Tries to retrieve the number of values for a specific header.
766    ///
767    /// # Arguments
768    ///
769    /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
770    ///
771    /// # Returns
772    ///
773    /// - `Option<usize>` - The count of values for the header if exists.
774    #[inline(always)]
775    pub fn try_get_header_size<K>(&self, key: K) -> Option<usize>
776    where
777        K: AsRef<str>,
778    {
779        self.headers.get(key.as_ref()).map(|values| values.len())
780    }
781
782    /// Retrieves the number of values for a specific header.
783    ///
784    /// # Arguments
785    ///
786    /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
787    ///
788    /// # Returns
789    ///
790    /// - `usize` - The count of values for the header.
791    ///
792    /// # Panics
793    ///
794    /// This function will panic if the header key is not found.
795    #[inline(always)]
796    pub fn get_header_size<K>(&self, key: K) -> usize
797    where
798        K: AsRef<str>,
799    {
800        self.try_get_header_size(key).unwrap()
801    }
802
803    /// Retrieves the total number of header values across all headers.
804    ///
805    /// # Returns
806    ///
807    /// - `usize` - The total count of all header values.
808    #[inline(always)]
809    pub fn get_headers_values_size(&self) -> usize {
810        self.headers.values().map(|values| values.len()).sum()
811    }
812
813    /// Retrieves the number of unique headers.
814    ///
815    /// # Returns
816    ///
817    /// - `usize` - The count of unique header keys.
818    #[inline(always)]
819    pub fn get_headers_size(&self) -> usize {
820        self.headers.len()
821    }
822
823    /// Checks if a specific header exists.
824    ///
825    /// # Arguments
826    ///
827    /// - `AsRef<str>` - The header key to check (must implement AsRef<str>).
828    ///
829    /// # Returns
830    ///
831    /// - `bool` - Whether the header exists.
832    #[inline(always)]
833    pub fn has_header<K>(&self, key: K) -> bool
834    where
835        K: AsRef<str>,
836    {
837        self.headers.contains_key(key.as_ref())
838    }
839
840    /// Checks if a header contains a specific value.
841    ///
842    /// # Arguments
843    ///
844    /// - `AsRef<str>` - The header key to check (must implement AsRef<str>).
845    /// - `AsRef<str>` - The value to search for (must implement AsRef<str>).
846    ///
847    /// # Returns
848    ///
849    /// - `bool` - Whether the header contains the value.
850    #[inline(always)]
851    pub fn has_header_value<K, V>(&self, key: K, value: V) -> bool
852    where
853        K: AsRef<str>,
854        V: AsRef<str>,
855    {
856        if let Some(values) = self.headers.get(key.as_ref()) {
857            values.iter().any(|v| v == value.as_ref())
858        } else {
859            false
860        }
861    }
862
863    /// Tries to parse cookies from the `Cookie` header.
864    ///
865    /// This method retrieves the `Cookie` header value and parses it into
866    /// a collection of key-value pairs representing the cookies.
867    ///
868    /// # Returns
869    ///
870    /// - `Option<Cookies>` - The parsed cookies if the header exists, otherwise `None`.
871    #[inline(always)]
872    pub fn try_get_cookies(&self) -> Option<Cookies> {
873        self.try_get_header_back(COOKIE)
874            .map(|cookie_header: String| Cookie::parse(cookie_header))
875    }
876
877    /// Parses cookies from the `Cookie` header.
878    ///
879    /// This method retrieves the `Cookie` header value and parses it into
880    /// a collection of key-value pairs representing the cookies.
881    ///
882    /// # Returns
883    ///
884    /// - `Cookies` - The parsed cookies.
885    ///
886    /// # Panics
887    ///
888    /// This function will panic if the `Cookie` header is not found.
889    #[inline(always)]
890    pub fn get_cookies(&self) -> Cookies {
891        self.try_get_cookies().unwrap()
892    }
893
894    /// Tries to get a cookie value by its key.
895    ///
896    /// This method first parses the cookies from the `Cookie` header,
897    /// then attempts to retrieve the value for the specified key.
898    ///
899    /// # Arguments
900    ///
901    /// - `AsRef<str>` - The cookie key (implements AsRef<str>).
902    ///
903    /// # Returns
904    ///
905    /// - `Option<CookieValue>` - The cookie value if exists.
906    #[inline(always)]
907    pub fn try_get_cookie<K>(&self, key: K) -> Option<CookieValue>
908    where
909        K: AsRef<str>,
910    {
911        self.try_get_cookies()
912            .and_then(|cookies: Cookies| cookies.get(key.as_ref()).cloned())
913    }
914
915    /// Gets a cookie value by its key.
916    ///
917    /// This method first parses the cookies from the `Cookie` header,
918    /// then retrieves the value for the specified key.
919    ///
920    /// # Arguments
921    ///
922    /// - `AsRef<str>` - The cookie key (implements AsRef<str>).
923    ///
924    /// # Returns
925    ///
926    /// - `CookieValue` - The cookie value.
927    ///
928    /// # Panics
929    ///
930    /// This function will panic if the `Cookie` header is not found
931    /// or the cookie key does not exist.
932    #[inline(always)]
933    pub fn get_cookie<K>(&self, key: K) -> CookieValue
934    where
935        K: AsRef<str>,
936    {
937        self.try_get_cookie(key).unwrap()
938    }
939
940    /// Retrieves the upgrade type from the request headers.
941    ///
942    /// This method looks for the `UPGRADE` header and attempts to parse its value
943    /// as_ref an `UpgradeType`. If the header is missing or the value is invalid,
944    /// it returns the default `UpgradeType`.
945    ///
946    /// # Returns
947    ///
948    /// - `UpgradeType` - The parsed upgrade type.
949    #[inline(always)]
950    pub fn get_upgrade_type(&self) -> UpgradeType {
951        self.try_get_header_back(UPGRADE)
952            .and_then(|data| data.parse::<UpgradeType>().ok())
953            .unwrap_or_default()
954    }
955
956    /// Retrieves the body content of the request as a UTF-8 encoded string.
957    ///
958    /// This method uses `String::from_utf8_lossy` to convert the byte slice returned by `self.get_body()` as a string.
959    /// If the byte slice contains invalid UTF-8 sequences, they will be replaced with the Unicode replacement character ().
960    ///
961    /// # Returns
962    ///
963    /// - `String` - The body content as a string.
964    #[inline(always)]
965    pub fn get_body_string(&self) -> String {
966        String::from_utf8_lossy(self.get_body()).into_owned()
967    }
968
969    /// Deserializes the body content of the request as_ref a specified type `T`.
970    ///
971    /// This method first retrieves the body content as a byte slice using `self.get_body()`.
972    /// It then attempts to deserialize the byte slice as_ref the specified type `T` using `json_from_slice`.
973    ///
974    /// # Arguments
975    ///
976    /// - `DeserializeOwned` - The target type to deserialize as_ref (must implement DeserializeOwned).
977    ///
978    /// # Returns
979    ///
980    /// - `Result<T, serde_json::Error>` - The deserialization result.
981    #[inline(always)]
982    pub fn try_get_body_json<T>(&self) -> Result<T, serde_json::Error>
983    where
984        T: DeserializeOwned,
985    {
986        serde_json::from_slice(self.get_body())
987    }
988
989    /// Deserializes the body content of the request as_ref a specified type `T`.
990    ///
991    /// This method first retrieves the body content as a byte slice using `self.get_body()`.
992    /// It then attempts to deserialize the byte slice as_ref the specified type `T` using `json_from_slice`.
993    ///
994    /// # Arguments
995    ///
996    /// - `DeserializeOwned` - The target type to deserialize as_ref (must implement DeserializeOwned).
997    ///
998    /// # Returns
999    ///
1000    /// - `T` - The deserialized body content.
1001    ///
1002    /// # Panics
1003    ///
1004    /// This function will panic if the deserialization fails.
1005    #[inline(always)]
1006    pub fn get_body_json<T>(&self) -> T
1007    where
1008        T: DeserializeOwned,
1009    {
1010        self.try_get_body_json().unwrap()
1011    }
1012
1013    /// Checks whether the WebSocket upgrade is enabled for this request.
1014    ///
1015    /// This method determines if the `UPGRADE` header indicates a WebSocket connection.
1016    ///
1017    /// # Returns
1018    ///
1019    /// - `bool` - Whether WebSocket upgrade is enabled.
1020    #[inline(always)]
1021    pub fn is_ws_upgrade_type(&self) -> bool {
1022        self.get_upgrade_type().is_ws()
1023    }
1024
1025    /// Checks if the current upgrade type is HTTP/2 cleartext (h2c).
1026    ///
1027    /// # Returns
1028    ///
1029    /// - `bool` - Whether the upgrade type is h2c.
1030    #[inline(always)]
1031    pub fn is_h2c_upgrade_type(&self) -> bool {
1032        self.get_upgrade_type().is_h2c()
1033    }
1034
1035    /// Checks if the current upgrade type is TLS (any version).
1036    ///
1037    /// # Returns
1038    ///
1039    /// - `bool` - Whether the upgrade type is TLS.
1040    #[inline(always)]
1041    pub fn is_tls_upgrade_type(&self) -> bool {
1042        self.get_upgrade_type().is_tls()
1043    }
1044
1045    /// Checks whether the upgrade type is unknown.
1046    ///
1047    /// # Returns
1048    ///
1049    /// - `bool` - Whether the upgrade type is unknown.
1050    #[inline(always)]
1051    pub fn is_unknown_upgrade_type(&self) -> bool {
1052        self.get_upgrade_type().is_unknown()
1053    }
1054
1055    /// Determines if a keep-alive connection should be enabled for this request.
1056    ///
1057    /// This function checks the `Connection` header and the HTTP version to determine
1058    /// if keep-alive should be enabled. The logic is as follows:
1059    ///
1060    /// 1. If the `Connection` header exists:
1061    ///    - Returns `true` if the header value is "keep-alive" (case-insensitive).
1062    ///    - Returns `false` if the header value is "close" (case-insensitive).
1063    /// 2. If no `Connection` header is present:
1064    ///    - Returns `true` if the HTTP version is 1.1 or higher.
1065    ///    - Returns `false` otherwise.
1066    ///
1067    /// # Returns
1068    ///
1069    /// - `bool` - Whether keep-alive should be enabled.
1070    #[inline(always)]
1071    pub fn is_enable_keep_alive(&self) -> bool {
1072        if let Some(connection_value) = self.try_get_header_back(CONNECTION) {
1073            if connection_value.eq_ignore_ascii_case(KEEP_ALIVE) {
1074                return true;
1075            } else if connection_value.eq_ignore_ascii_case(CLOSE) {
1076                return self.is_ws_upgrade_type();
1077            }
1078        }
1079        self.get_version().is_http1_1_or_higher() || self.is_ws_upgrade_type()
1080    }
1081
1082    /// Determines if keep-alive should be disabled for this request.
1083    ///
1084    /// # Returns
1085    ///
1086    /// - `bool` - Whether keep-alive should be disabled.
1087    #[inline(always)]
1088    pub fn is_disable_keep_alive(&self) -> bool {
1089        !self.is_enable_keep_alive()
1090    }
1091}