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::ServerClosedConnection(status) => *status,
122 Self::IncompleteWebSocketFrame(status) => *status,
123 Self::RequestTooLong(status) => *status,
124 Self::PathTooLong(status) => *status,
125 Self::QueryTooLong(status) => *status,
126 Self::HeaderLineTooLong(status) => *status,
127 Self::TooManyHeaders(status) => *status,
128 Self::HeaderKeyTooLong(status) => *status,
129 Self::HeaderValueTooLong(status) => *status,
130 Self::ContentLengthTooLarge(status) => *status,
131 Self::InvalidContentLength(status) => *status,
132 Self::InvalidUrlScheme(status) => *status,
133 Self::InvalidUrlHost(status) => *status,
134 Self::InvalidUrlPort(status) => *status,
135 Self::InvalidUrlPath(status) => *status,
136 Self::InvalidUrlQuery(status) => *status,
137 Self::InvalidUrlFragment(status) => *status,
138 Self::ReadTimeout(status) => *status,
139 Self::WriteTimeout(status) => *status,
140 Self::TcpConnectionFailed(status) => *status,
141 Self::TlsHandshakeFailed(status) => *status,
142 Self::TlsCertificateInvalid(status) => *status,
143 Self::WebSocketFrameTooLarge(status) => *status,
144 Self::WebSocketOpcodeUnsupported(status) => *status,
145 Self::WebSocketMaskMissing(status) => *status,
146 Self::WebSocketPayloadCorrupted(status) => *status,
147 Self::WebSocketInvalidUtf8(status) => *status,
148 Self::WebSocketInvalidCloseCode(status) => *status,
149 Self::WebSocketInvalidExtension(status) => *status,
150 Self::HttpRequestPartsInsufficient(status) => *status,
151 Self::TcpStreamConnect(status) => *status,
152 Self::TlsConnectorBuild(status) => *status,
153 Self::InvalidUrl(status) => *status,
154 Self::ConfigReadError(status) => *status,
155 Self::TcpStreamConnectString(status) => *status,
156 Self::TlsConnectorBuildString(status) => *status,
157 Self::Request(_) => HttpStatus::BadRequest,
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(Method::Unknown(method_str.to_string()));
313 let version: RequestVersion = version_str
314 .parse::<RequestVersion>()
315 .unwrap_or(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, |query_index: usize| {
358 let temp: &str = &path[query_index + 1..];
359 match hash_index {
360 None => temp,
361 Some(hash_index) if hash_index <= query_index => temp,
362 Some(hash_index) => &temp[..hash_index - query_index - 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(separator_index) => path[..separator_index].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(|header_values: &VecDeque<String>| header_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(|header_values: &VecDeque<String>| header_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
780 .get(key.as_ref())
781 .map(|header_values: &VecDeque<String>| header_values.len())
782 }
783
784 /// Retrieves the number of values for a specific header.
785 ///
786 /// # Arguments
787 ///
788 /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
789 ///
790 /// # Returns
791 ///
792 /// - `usize` - The count of values for the header.
793 ///
794 /// # Panics
795 ///
796 /// This function will panic if the header key is not found.
797 #[inline(always)]
798 pub fn get_header_size<K>(&self, key: K) -> usize
799 where
800 K: AsRef<str>,
801 {
802 self.try_get_header_size(key).unwrap()
803 }
804
805 /// Retrieves the total number of header values across all headers.
806 ///
807 /// # Returns
808 ///
809 /// - `usize` - The total count of all header values.
810 #[inline(always)]
811 pub fn get_headers_values_size(&self) -> usize {
812 self.headers
813 .values()
814 .map(|header_values: &VecDeque<String>| header_values.len())
815 .sum()
816 }
817
818 /// Retrieves the number of unique headers.
819 ///
820 /// # Returns
821 ///
822 /// - `usize` - The count of unique header keys.
823 #[inline(always)]
824 pub fn get_headers_size(&self) -> usize {
825 self.headers.len()
826 }
827
828 /// Checks if a specific header exists.
829 ///
830 /// # Arguments
831 ///
832 /// - `AsRef<str>` - The header key to check (must implement AsRef<str>).
833 ///
834 /// # Returns
835 ///
836 /// - `bool` - Whether the header exists.
837 #[inline(always)]
838 pub fn has_header<K>(&self, key: K) -> bool
839 where
840 K: AsRef<str>,
841 {
842 self.headers.contains_key(key.as_ref())
843 }
844
845 /// Checks if a header contains a specific value.
846 ///
847 /// # Arguments
848 ///
849 /// - `AsRef<str>` - The header key to check (must implement AsRef<str>).
850 /// - `AsRef<str>` - The value to search for (must implement AsRef<str>).
851 ///
852 /// # Returns
853 ///
854 /// - `bool` - Whether the header contains the value.
855 #[inline(always)]
856 pub fn has_header_value<K, V>(&self, key: K, value: V) -> bool
857 where
858 K: AsRef<str>,
859 V: AsRef<str>,
860 {
861 if let Some(values) = self.headers.get(key.as_ref()) {
862 values.iter().any(|data: &String| data == value.as_ref())
863 } else {
864 false
865 }
866 }
867
868 /// Tries to parse cookies from the `Cookie` header.
869 ///
870 /// This method retrieves the `Cookie` header value and parses it into
871 /// a collection of key-value pairs representing the cookies.
872 ///
873 /// # Returns
874 ///
875 /// - `Option<Cookies>` - The parsed cookies if the header exists, otherwise `None`.
876 #[inline(always)]
877 pub fn try_get_cookies(&self) -> Option<Cookies> {
878 self.try_get_header_back(COOKIE)
879 .map(|cookie_header: String| Cookie::parse(cookie_header))
880 }
881
882 /// Parses cookies from the `Cookie` header.
883 ///
884 /// This method retrieves the `Cookie` header value and parses it into
885 /// a collection of key-value pairs representing the cookies.
886 ///
887 /// # Returns
888 ///
889 /// - `Cookies` - The parsed cookies.
890 ///
891 /// # Panics
892 ///
893 /// This function will panic if the `Cookie` header is not found.
894 #[inline(always)]
895 pub fn get_cookies(&self) -> Cookies {
896 self.try_get_cookies().unwrap()
897 }
898
899 /// Tries to get a cookie value by its key.
900 ///
901 /// This method first parses the cookies from the `Cookie` header,
902 /// then attempts to retrieve the value for the specified key.
903 ///
904 /// # Arguments
905 ///
906 /// - `AsRef<str>` - The cookie key (implements AsRef<str>).
907 ///
908 /// # Returns
909 ///
910 /// - `Option<CookieValue>` - The cookie value if exists.
911 #[inline(always)]
912 pub fn try_get_cookie<K>(&self, key: K) -> Option<CookieValue>
913 where
914 K: AsRef<str>,
915 {
916 self.try_get_cookies()
917 .and_then(|cookies: Cookies| cookies.get(key.as_ref()).cloned())
918 }
919
920 /// Gets a cookie value by its key.
921 ///
922 /// This method first parses the cookies from the `Cookie` header,
923 /// then retrieves the value for the specified key.
924 ///
925 /// # Arguments
926 ///
927 /// - `AsRef<str>` - The cookie key (implements AsRef<str>).
928 ///
929 /// # Returns
930 ///
931 /// - `CookieValue` - The cookie value.
932 ///
933 /// # Panics
934 ///
935 /// This function will panic if the `Cookie` header is not found
936 /// or the cookie key does not exist.
937 #[inline(always)]
938 pub fn get_cookie<K>(&self, key: K) -> CookieValue
939 where
940 K: AsRef<str>,
941 {
942 self.try_get_cookie(key).unwrap()
943 }
944
945 /// Retrieves the upgrade type from the request headers.
946 ///
947 /// This method looks for the `UPGRADE` header and attempts to parse its value
948 /// as_ref an `UpgradeType`. If the header is missing or the value is invalid,
949 /// it returns the default `UpgradeType`.
950 ///
951 /// # Returns
952 ///
953 /// - `UpgradeType` - The parsed upgrade type.
954 #[inline(always)]
955 pub fn get_upgrade_type(&self) -> UpgradeType {
956 self.try_get_header_back(UPGRADE)
957 .and_then(|data: String| data.parse::<UpgradeType>().ok())
958 .unwrap_or_default()
959 }
960
961 /// Retrieves the body content of the request as a UTF-8 encoded string.
962 ///
963 /// This method uses `String::from_utf8_lossy` to convert the byte slice returned by `self.get_body()` as a string.
964 /// If the byte slice contains invalid UTF-8 sequences, they will be replaced with the Unicode replacement character ().
965 ///
966 /// # Returns
967 ///
968 /// - `String` - The body content as a string.
969 #[inline(always)]
970 pub fn get_body_string(&self) -> String {
971 String::from_utf8_lossy(self.get_body()).into_owned()
972 }
973
974 /// Deserializes the body content of the request as_ref a specified type `T`.
975 ///
976 /// This method first retrieves the body content as a byte slice using `self.get_body()`.
977 /// It then attempts to deserialize the byte slice as_ref the specified type `T` using `json_from_slice`.
978 ///
979 /// # Arguments
980 ///
981 /// - `DeserializeOwned` - The target type to deserialize as_ref (must implement DeserializeOwned).
982 ///
983 /// # Returns
984 ///
985 /// - `Result<T, serde_json::Error>` - The deserialization result.
986 #[inline(always)]
987 pub fn try_get_body_json<T>(&self) -> Result<T, serde_json::Error>
988 where
989 T: DeserializeOwned,
990 {
991 serde_json::from_slice(self.get_body())
992 }
993
994 /// Deserializes the body content of the request as_ref a specified type `T`.
995 ///
996 /// This method first retrieves the body content as a byte slice using `self.get_body()`.
997 /// It then attempts to deserialize the byte slice as_ref the specified type `T` using `json_from_slice`.
998 ///
999 /// # Arguments
1000 ///
1001 /// - `DeserializeOwned` - The target type to deserialize as_ref (must implement DeserializeOwned).
1002 ///
1003 /// # Returns
1004 ///
1005 /// - `T` - The deserialized body content.
1006 ///
1007 /// # Panics
1008 ///
1009 /// This function will panic if the deserialization fails.
1010 #[inline(always)]
1011 pub fn get_body_json<T>(&self) -> T
1012 where
1013 T: DeserializeOwned,
1014 {
1015 self.try_get_body_json().unwrap()
1016 }
1017
1018 /// Checks whether the WebSocket upgrade is enabled for this request.
1019 ///
1020 /// This method determines if the `UPGRADE` header indicates a WebSocket connection.
1021 ///
1022 /// # Returns
1023 ///
1024 /// - `bool` - Whether WebSocket upgrade is enabled.
1025 #[inline(always)]
1026 pub fn is_ws_upgrade_type(&self) -> bool {
1027 self.get_upgrade_type().is_ws()
1028 }
1029
1030 /// Checks if the current upgrade type is HTTP/2 cleartext (h2c).
1031 ///
1032 /// # Returns
1033 ///
1034 /// - `bool` - Whether the upgrade type is h2c.
1035 #[inline(always)]
1036 pub fn is_h2c_upgrade_type(&self) -> bool {
1037 self.get_upgrade_type().is_h2c()
1038 }
1039
1040 /// Checks if the current upgrade type is TLS (any version).
1041 ///
1042 /// # Returns
1043 ///
1044 /// - `bool` - Whether the upgrade type is TLS.
1045 #[inline(always)]
1046 pub fn is_tls_upgrade_type(&self) -> bool {
1047 self.get_upgrade_type().is_tls()
1048 }
1049
1050 /// Checks whether the upgrade type is unknown.
1051 ///
1052 /// # Returns
1053 ///
1054 /// - `bool` - Whether the upgrade type is unknown.
1055 #[inline(always)]
1056 pub fn is_unknown_upgrade_type(&self) -> bool {
1057 self.get_upgrade_type().is_unknown()
1058 }
1059
1060 /// Determines if a keep-alive connection should be enabled for this request.
1061 ///
1062 /// This function checks the `Connection` header and the HTTP version to determine
1063 /// if keep-alive should be enabled. The logic is as follows:
1064 ///
1065 /// 1. If the `Connection` header exists:
1066 /// - Returns `true` if the header value is "keep-alive" (case-insensitive).
1067 /// - Returns `false` if the header value is "close" (case-insensitive).
1068 /// 2. If no `Connection` header is present:
1069 /// - Returns `true` if the HTTP version is 1.1 or higher.
1070 /// - Returns `false` otherwise.
1071 ///
1072 /// # Returns
1073 ///
1074 /// - `bool` - Whether keep-alive should be enabled.
1075 #[inline(always)]
1076 pub fn is_enable_keep_alive(&self) -> bool {
1077 if let Some(connection_value) = self.try_get_header_back(CONNECTION) {
1078 if connection_value.eq_ignore_ascii_case(KEEP_ALIVE) {
1079 return true;
1080 } else if connection_value.eq_ignore_ascii_case(CLOSE) {
1081 return self.is_ws_upgrade_type();
1082 }
1083 }
1084 self.get_version().is_http1_1_or_higher() || self.is_ws_upgrade_type()
1085 }
1086
1087 /// Determines if keep-alive should be disabled for this request.
1088 ///
1089 /// # Returns
1090 ///
1091 /// - `bool` - Whether keep-alive should be disabled.
1092 #[inline(always)]
1093 pub fn is_disable_keep_alive(&self) -> bool {
1094 !self.is_enable_keep_alive()
1095 }
1096}