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::Unknown(status) => *status,
158 }
159 }
160
161 /// Gets the numeric HTTP status code associated with this error.
162 ///
163 /// Returns the numeric status code (e.g., 400, 404, 500) that corresponds to this error.
164 ///
165 /// # Returns
166 ///
167 /// - `ResponseStatusCode` - The numeric HTTP status code.
168 pub fn get_http_status_code(&self) -> ResponseStatusCode {
169 self.get_http_status().code()
170 }
171}
172
173/// Implementation of `Default` trait for `RequestConfig`.
174impl Default for RequestConfig {
175 /// Creates a new `RequestConfig` with default secure settings.
176 ///
177 /// This constructor initializes the configuration with standard security limits
178 /// suitable for most HTTP request parsing scenarios.
179 ///
180 /// # Returns
181 ///
182 /// - `Self` - A new `RequestConfig` instance with default settings.
183 #[inline(always)]
184 fn default() -> Self {
185 Self {
186 buffer_size: DEFAULT_BUFFER_SIZE,
187 max_path_size: DEFAULT_MAX_PATH_SIZE,
188 max_header_count: DEFAULT_MAX_HEADER_COUNT,
189 max_header_key_size: DEFAULT_MAX_HEADER_KEY_SIZE,
190 max_header_value_size: DEFAULT_MAX_HEADER_VALUE_SIZE,
191 max_body_size: DEFAULT_MAX_BODY_SIZE,
192 read_timeout_ms: DEFAULT_READ_TIMEOUT_MS,
193 }
194 }
195}
196
197impl RequestConfig {
198 /// Creates a new `RequestConfig` from a JSON string.
199 ///
200 /// # Arguments
201 ///
202 /// - `AsRef<str>` - The configuration.
203 ///
204 /// # Returns
205 ///
206 /// - `Result<RequestConfig, serde_json::Error>` - The parsed `RequestConfig` or an error.
207 pub fn from_json<C>(json: C) -> Result<RequestConfig, serde_json::Error>
208 where
209 C: AsRef<str>,
210 {
211 serde_json::from_str(json.as_ref())
212 }
213
214 /// Creates a new `RequestConfig` with low-security settings.
215 ///
216 /// This constructor initializes the configuration with less restrictive limits
217 /// for environments where higher limits are needed.
218 ///
219 /// # Returns
220 ///
221 /// - `Self` - A new `RequestConfig` instance with low-security settings.
222 #[inline(always)]
223 pub fn low_security() -> Self {
224 Self {
225 buffer_size: DEFAULT_LOW_SECURITY_BUFFER_SIZE,
226 max_path_size: DEFAULT_LOW_SECURITY_MAX_PATH_SIZE,
227 max_header_count: DEFAULT_LOW_SECURITY_MAX_HEADER_COUNT,
228 max_header_key_size: DEFAULT_LOW_SECURITY_MAX_HEADER_KEY_SIZE,
229 max_header_value_size: DEFAULT_LOW_SECURITY_MAX_HEADER_VALUE_SIZE,
230 max_body_size: DEFAULT_LOW_SECURITY_MAX_BODY_SIZE,
231 read_timeout_ms: DEFAULT_LOW_SECURITY_READ_TIMEOUT_MS,
232 }
233 }
234
235 /// Creates a new `RequestConfig` with high-security settings.
236 ///
237 /// This constructor initializes the configuration with more restrictive limits
238 /// to provide maximum protection against various attacks in high-risk environments.
239 ///
240 /// # Returns
241 ///
242 /// - `Self` - A new `RequestConfig` instance with high-security settings.
243 #[inline(always)]
244 pub fn high_security() -> Self {
245 Self {
246 buffer_size: DEFAULT_HIGH_SECURITY_BUFFER_SIZE,
247 max_path_size: DEFAULT_HIGH_SECURITY_MAX_PATH_SIZE,
248 max_header_count: DEFAULT_HIGH_SECURITY_MAX_HEADER_COUNT,
249 max_header_key_size: DEFAULT_HIGH_SECURITY_MAX_HEADER_KEY_SIZE,
250 max_header_value_size: DEFAULT_HIGH_SECURITY_MAX_HEADER_VALUE_SIZE,
251 max_body_size: DEFAULT_HIGH_SECURITY_MAX_BODY_SIZE,
252 read_timeout_ms: DEFAULT_HIGH_SECURITY_READ_TIMEOUT_MS,
253 }
254 }
255}
256
257/// Provides a default value for `Request`.
258///
259/// Returns a new `Request` instance with all fields initialized to their default values.
260impl Default for Request {
261 #[inline(always)]
262 fn default() -> Self {
263 Self {
264 method: Method::default(),
265 host: String::new(),
266 version: HttpVersion::default(),
267 path: String::new(),
268 querys: hash_map_xx_hash3_64(),
269 headers: hash_map_xx_hash3_64(),
270 body: Vec::new(),
271 }
272 }
273}
274
275impl Http {
276 /// Parses the first line of HTTP request into method, path, and version components.
277 ///
278 /// # Arguments
279 ///
280 /// - `&str`: The first line string of HTTP request to parse.
281 ///
282 /// # Returns
283 ///
284 /// - `Result<(RequestMethod, &str, RequestVersion), RequestError>`: A tuple containing:
285 /// - The parsed HTTP method
286 /// - The full path string
287 /// - The parsed HTTP version
288 /// - Or an error if parsing fails
289 #[inline(always)]
290 fn parse_first_line(line: &str) -> Result<(RequestMethod, &str, RequestVersion), RequestError> {
291 let mut parts: SplitWhitespace<'_> = line.split_whitespace();
292 let method_str: &str = parts
293 .next()
294 .ok_or(RequestError::HttpRequestPartsInsufficient(
295 HttpStatus::BadRequest,
296 ))?;
297 let full_path: &str = parts
298 .next()
299 .ok_or(RequestError::HttpRequestPartsInsufficient(
300 HttpStatus::BadRequest,
301 ))?;
302 let version_str: &str = parts
303 .next()
304 .ok_or(RequestError::HttpRequestPartsInsufficient(
305 HttpStatus::BadRequest,
306 ))?;
307 let method: RequestMethod = method_str
308 .parse::<RequestMethod>()
309 .unwrap_or_else(|_| Method::Unknown(method_str.to_string()));
310 let version: RequestVersion = version_str
311 .parse::<RequestVersion>()
312 .unwrap_or_else(|_| RequestVersion::Unknown(version_str.to_string()));
313 Ok((method, full_path, version))
314 }
315
316 /// Validates the path length against the maximum allowed size.
317 ///
318 /// # Arguments
319 ///
320 /// - `&str`: The path string to check.
321 /// - `usize`: The maximum allowed path size.
322 ///
323 /// # Returns
324 ///
325 /// - `Result<(), RequestError>`: Ok if valid, or an error if the path is too long.
326 #[inline(always)]
327 fn check_path_size(path: &str, max_size: usize) -> Result<(), RequestError> {
328 if path.len() > max_size && max_size != DEFAULT_LOW_SECURITY_MAX_PATH_SIZE {
329 return Err(RequestError::PathTooLong(HttpStatus::URITooLong));
330 }
331 Ok(())
332 }
333
334 /// Parses the query string from the full path.
335 ///
336 /// Handles both query parameters (after `?`) and hash fragments (after `#`),
337 /// ensuring proper parsing when both are present.
338 ///
339 /// # Arguments
340 ///
341 /// - `&str`: The full path string containing the query.
342 /// - `Option<usize>`: The index of the query separator (`?`), if present.
343 /// - `Option<usize>`: The index of the hash separator (`#`), if present.
344 ///
345 /// # Returns
346 ///
347 /// - `&str`: The parsed query string slice, or empty string if no query.
348 #[inline(always)]
349 fn get_query_slice<'a>(
350 path: &'a str,
351 query_index: Option<usize>,
352 hash_index: Option<usize>,
353 ) -> &'a str {
354 query_index.map_or(EMPTY_STR, |i: usize| {
355 let temp: &'a str = &path[i + 1..];
356 match hash_index {
357 None => temp,
358 Some(hash_idx) if hash_idx <= i => temp,
359 Some(hash_idx) => &temp[..hash_idx - i - 1],
360 }
361 })
362 }
363
364 /// Parses the request path without query string or hash fragment.
365 ///
366 /// # Arguments
367 ///
368 /// - `&str`: The full path string.
369 /// - `Option<usize>`: The index of the query separator (`?`), if present.
370 /// - `Option<usize>`: The index of the hash separator (`#`), if present.
371 ///
372 /// # Returns
373 ///
374 /// - `RequestPath`: The request path without query or hash.
375 #[inline(always)]
376 fn parse_path(
377 path: &str,
378 query_index: Option<usize>,
379 hash_index: Option<usize>,
380 ) -> RequestPath {
381 match query_index.or(hash_index) {
382 Some(i) => path[..i].to_owned(),
383 None => path.to_owned(),
384 }
385 }
386
387 /// Parses a query string as_ref key-value pairs.
388 ///
389 /// Expects format "key1=value1&key2=value2". Empty values are allowed.
390 ///
391 /// # Arguments
392 ///
393 /// - `&str` - The query string to parse.
394 ///
395 /// # Returns
396 ///
397 /// - `RequestQuerys` - The parsed query parameters.
398 #[inline(always)]
399 fn parse_querys(query: &str) -> RequestQuerys {
400 let estimated_capacity: usize = query.matches(AND).count() + 1;
401 let mut query_map: RequestQuerys = HashMapXxHash3_64::with_capacity_and_hasher(
402 estimated_capacity,
403 BuildHasherDefault::default(),
404 );
405 for pair in query.split(AND) {
406 if let Some((key, value)) = pair.split_once(EQUAL) {
407 if !key.is_empty() {
408 query_map.insert(key.to_string(), value.to_string());
409 }
410 } else if !pair.is_empty() {
411 query_map.insert(pair.to_string(), String::new());
412 }
413 }
414 query_map
415 }
416
417 /// Checks if the header count exceeds the maximum allowed.
418 ///
419 /// # Arguments
420 ///
421 /// - `usize`: The current number of headers parsed.
422 /// - `usize`: The maximum allowed number of headers.
423 ///
424 /// # Returns
425 ///
426 /// - `Result<(), RequestError>`: Returns an error if the limit is exceeded and not in low security mode.
427 #[inline(always)]
428 fn check_header_count(count: usize, max_count: usize) -> Result<(), RequestError> {
429 if count > max_count && max_count != DEFAULT_LOW_SECURITY_MAX_HEADER_COUNT {
430 return Err(RequestError::TooManyHeaders(
431 HttpStatus::RequestHeaderFieldsTooLarge,
432 ));
433 }
434 Ok(())
435 }
436
437 /// Checks if a header key exceeds the maximum allowed length.
438 ///
439 /// # Arguments
440 ///
441 /// - `&str`: The header key to check.
442 /// - `usize`: The maximum allowed length for a header key.
443 ///
444 /// # Returns
445 ///
446 /// - `Result<(), RequestError>`: Returns an error if the limit is exceeded and not in low security mode.
447 #[inline(always)]
448 fn check_header_key_size(key: &str, max_size: usize) -> Result<(), RequestError> {
449 if key.len() > max_size && max_size != DEFAULT_LOW_SECURITY_MAX_HEADER_KEY_SIZE {
450 return Err(RequestError::HeaderKeyTooLong(
451 HttpStatus::RequestHeaderFieldsTooLarge,
452 ));
453 }
454 Ok(())
455 }
456
457 /// Checks if a header value exceeds the maximum allowed length.
458 ///
459 /// # Arguments
460 ///
461 /// - `&str`: The header value to check.
462 /// - `usize`: The maximum allowed length for a header value.
463 ///
464 /// # Returns
465 ///
466 /// - `Result<(), RequestError>`: Returns an error if the limit is exceeded and not in low security mode.
467 #[inline(always)]
468 fn check_header_value_size(value: &str, max_size: usize) -> Result<(), RequestError> {
469 if value.len() > max_size && max_size != DEFAULT_LOW_SECURITY_MAX_HEADER_VALUE_SIZE {
470 return Err(RequestError::HeaderValueTooLong(
471 HttpStatus::RequestHeaderFieldsTooLarge,
472 ));
473 }
474 Ok(())
475 }
476
477 /// Parses the Content-Length header value and checks it against max body size.
478 ///
479 /// # Arguments
480 ///
481 /// - `&str`: The Content-Length header value string.
482 /// - `usize`: The maximum allowed body size.
483 ///
484 /// # Returns
485 ///
486 /// - `Result<usize, RequestError>`: The parsed content length or an error.
487 #[inline(always)]
488 fn check_body_size(value: &str, max_size: usize) -> Result<usize, RequestError> {
489 let length: usize = value.parse::<usize>()?;
490 if length > max_size && max_size != DEFAULT_LOW_SECURITY_MAX_BODY_SIZE {
491 return Err(RequestError::ContentLengthTooLarge(
492 HttpStatus::PayloadTooLarge,
493 ));
494 }
495 Ok(length)
496 }
497
498 /// Parses HTTP headers from a buffered reader.
499 ///
500 /// This method reads header lines from the provided buffered reader until an empty line
501 /// is encountered, which indicates the end of headers. It checks header count, length,
502 /// and content according to the provided configuration.
503 ///
504 /// # Arguments
505 ///
506 /// - `&mut AsyncBufReadExt + Unpin`: A mutable reference to a buffered reader implementing `AsyncBufReadExt`.
507 /// - `&RequestConfig`: Configuration for security limits and buffer settings.
508 ///
509 /// # Returns
510 ///
511 /// - `Result<(RequestHeaders, RequestHost, usize), RequestError>`: A tuple containing:
512 /// - The parsed headers as a hash map
513 /// - The host value parsed from the Host header
514 /// - The content length parsed from the Content-Length header
515 /// - Or an error if parsing fails
516 async fn parse_headers<R>(
517 reader: &mut R,
518 config: &RequestConfig,
519 ) -> Result<(RequestHeaders, RequestHost, usize), RequestError>
520 where
521 R: AsyncBufReadExt + Unpin,
522 {
523 let buffer_size: usize = config.get_buffer_size();
524 let max_header_count: usize = config.get_max_header_count();
525 let max_header_key_size: usize = config.get_max_header_key_size();
526 let max_header_value_size: usize = config.get_max_header_value_size();
527 let max_body_size: usize = config.get_max_body_size();
528 let mut headers: RequestHeaders =
529 HashMapXxHash3_64::with_capacity_and_hasher(B_16, BuildHasherDefault::default());
530 let mut host: RequestHost = String::new();
531 let mut content_size: usize = 0;
532 let mut header_count: usize = 0;
533 let mut header_line_buffer: String = String::with_capacity(buffer_size);
534 loop {
535 header_line_buffer.clear();
536 AsyncBufReadExt::read_line(reader, &mut header_line_buffer).await?;
537 let header_line: &str = header_line_buffer.trim();
538 if header_line.is_empty() {
539 break;
540 }
541 header_count += 1;
542 Self::check_header_count(header_count, max_header_count)?;
543 let (key_part, value_part): (&str, &str) = match header_line.split_once(COLON) {
544 Some(parts) => parts,
545 None => continue,
546 };
547 let key_trimmed: &str = key_part.trim();
548 if key_trimmed.is_empty() {
549 continue;
550 }
551 let key: String = key_trimmed.to_ascii_lowercase();
552 Self::check_header_key_size(&key, max_header_key_size)?;
553 let value: String = value_part.trim().to_string();
554 Self::check_header_value_size(&value, max_header_value_size)?;
555 match key.as_str() {
556 HOST => host = value.clone(),
557 CONTENT_LENGTH => {
558 content_size = Self::check_body_size(&value, max_body_size)?;
559 }
560 _ => {}
561 }
562 headers.entry(key).or_default().push_back(value);
563 }
564 Ok((headers, host, content_size))
565 }
566
567 /// Reads the request body from the buffered reader.
568 ///
569 /// # Arguments
570 ///
571 /// - `&mut BufReader<&mut TcpStream>`: The buffered reader to read from.
572 /// - `usize`: The expected content size.
573 ///
574 /// # Returns
575 ///
576 /// - `Result<RequestBody, RequestError>`: The body bytes or an error.
577 #[inline(always)]
578 async fn parse_body(
579 reader: &mut BufReader<&mut TcpStream>,
580 content_size: usize,
581 ) -> Result<RequestBody, RequestError> {
582 let mut body: RequestBody = Vec::with_capacity(content_size);
583 if content_size > 0 {
584 body.resize(content_size, 0);
585 AsyncReadExt::read_exact(reader, &mut body).await?;
586 }
587 Ok(body)
588 }
589
590 /// Parses the HTTP request content from the stream.
591 ///
592 /// This is an internal helper function that performs the actual parsing.
593 ///
594 /// # Arguments
595 ///
596 /// - `&ArcRwLock<TcpStream>`: The TCP stream to read from.
597 /// - `&RequestConfig`: Configuration for security limits and buffer settings.
598 ///
599 /// # Returns
600 ///
601 /// - `Result<Request, RequestError>`: The parsed request or an error.
602 async fn parse_from_stream(
603 stream: &ArcRwLockStream,
604 config: &RequestConfig,
605 ) -> Result<Request, RequestError> {
606 let buffer_size: usize = config.get_buffer_size();
607 let max_path_size: usize = config.get_max_path_size();
608 let mut buf_stream: RwLockWriteGuard<'_, TcpStream> = stream.write().await;
609 let reader: &mut BufReader<&mut TcpStream> =
610 &mut BufReader::with_capacity(buffer_size, &mut buf_stream);
611 let mut line: String = String::with_capacity(buffer_size);
612 AsyncBufReadExt::read_line(reader, &mut line).await?;
613 let (method, path, version): (RequestMethod, &str, RequestVersion) =
614 Self::parse_first_line(&line)?;
615 Self::check_path_size(path, max_path_size)?;
616 let hash_index: Option<usize> = path.find(HASH);
617 let query_index: Option<usize> = path.find(QUERY);
618 let query_slice: &str = Self::get_query_slice(path, query_index, hash_index);
619 let querys: RequestQuerys = Self::parse_querys(query_slice);
620 let path: RequestPath = Self::parse_path(path, query_index, hash_index);
621 let (headers, host, content_size): (RequestHeaders, RequestHost, usize) =
622 Self::parse_headers(reader, config).await?;
623 let body: RequestBody = Self::parse_body(reader, content_size).await?;
624 Ok(Request {
625 method,
626 host,
627 version,
628 path,
629 querys,
630 headers,
631 body,
632 })
633 }
634}
635
636impl Ws {
637 /// Reads data from the stream with optional timeout handling.
638 ///
639 /// # Arguments
640 ///
641 /// - `&ArcRwLockStream`: The TCP stream to read from.
642 /// - `&mut [u8]`: The buffer to read data into.
643 /// - `Option<Duration>`: The optional timeout duration. If Some, timeout is applied; if None, no timeout.
644 /// - `&mut bool`: Mutable reference to track if we got a client response.
645 ///
646 /// # Returns
647 ///
648 /// - `Result<Option<usize>, RequestError>`: The number of bytes read, None for timeout/ping, or an error.
649 async fn read(
650 stream: &ArcRwLockStream,
651 buffer: &mut [u8],
652 duration_opt: Option<Duration>,
653 is_client_response: &mut bool,
654 ) -> Result<Option<usize>, RequestError> {
655 if let Some(duration) = duration_opt {
656 return match timeout(duration, stream.write().await.read(buffer)).await {
657 Ok(result) => match result {
658 Ok(len) => Ok(Some(len)),
659 Err(error) => Err(error.into()),
660 },
661 Err(error) => {
662 if !*is_client_response {
663 return Err(error.into());
664 }
665 *is_client_response = false;
666 stream.try_send_body(&PING_FRAME).await?;
667 Ok(None)
668 }
669 };
670 }
671 match stream.write().await.read(buffer).await {
672 Ok(len) => Ok(Some(len)),
673 Err(error) => Err(error.into()),
674 }
675 }
676
677 /// Handles a decoded WebSocket Text or Binary frame and accumulates payload data.
678 ///
679 /// # Arguments
680 ///
681 /// - `&Request`: The request to update on completion.
682 /// - `&WebSocketFrame`: The decoded WebSocket frame.
683 /// - `&mut Vec<u8>`: The accumulated frame data.
684 ///
685 /// # Returns
686 ///
687 /// - `Result<Option<Request>, RequestError>`: Some(request) if frame is complete, None to continue, or error.
688 #[inline(always)]
689 fn parse_frame(
690 request: &Request,
691 frame: &WebSocketFrame,
692 full_frame: &mut Vec<u8>,
693 ) -> Result<Option<Request>, RequestError> {
694 let payload_data: &[u8] = frame.get_payload_data();
695 full_frame.extend_from_slice(payload_data);
696 if *frame.get_fin() {
697 let mut result: Request = request.clone();
698 result.body = full_frame.clone();
699 return Ok(Some(result));
700 }
701 Ok(None)
702 }
703}
704
705impl Request {
706 /// Parses an HTTP request from a TCP stream.
707 ///
708 /// Wraps the stream in a buffered reader and delegates to `http_from_reader`.
709 /// If the timeout is DEFAULT_LOW_SECURITY_READ_TIMEOUT_MS, no timeout is applied.
710 ///
711 /// # Arguments
712 ///
713 /// - `&ArcRwLock<TcpStream>` - The TCP stream to read from.
714 /// - `&RequestConfig` - Configuration for security limits and buffer settings.
715 ///
716 /// # Returns
717 ///
718 /// - `Result<Request, RequestError>` - The parsed request or an error.
719 pub async fn http_from_stream(
720 stream: &ArcRwLockStream,
721 config: &RequestConfig,
722 ) -> Result<Request, RequestError> {
723 let timeout_ms: u64 = config.get_read_timeout_ms();
724 if timeout_ms == DEFAULT_LOW_SECURITY_READ_TIMEOUT_MS {
725 return Http::parse_from_stream(stream, config).await;
726 }
727 let duration: Duration = Duration::from_millis(timeout_ms);
728 timeout(duration, Http::parse_from_stream(stream, config)).await?
729 }
730
731 /// Parses a WebSocket request from a TCP stream.
732 ///
733 /// Wraps the stream in a buffered reader and delegates to `ws_from_reader`.
734 /// If the timeout is DEFAULT_LOW_SECURITY_READ_TIMEOUT_MS, no timeout is applied.
735 ///
736 /// # Arguments
737 ///
738 /// - `&ArcRwLock<TcpStream>`: The TCP stream to read from.
739 /// - `&RequestConfig`: Configuration for security limits and buffer settings.
740 ///
741 /// # Returns
742 ///
743 /// - `Result<Request, RequestError>`: The parsed WebSocket request or an error.
744 pub async fn ws_from_stream(
745 &self,
746 stream: &ArcRwLockStream,
747 config: &RequestConfig,
748 ) -> Result<Request, RequestError> {
749 let buffer_size: usize = config.get_buffer_size();
750 let read_timeout_ms: u64 = config.get_read_timeout_ms();
751 let mut dynamic_buffer: Vec<u8> = Vec::with_capacity(buffer_size);
752 let mut temp_buffer: Vec<u8> = vec![0; buffer_size];
753 let mut full_frame: Vec<u8> = Vec::new();
754 let mut is_client_response: bool = false;
755 let duration_opt: Option<Duration> =
756 if read_timeout_ms == DEFAULT_LOW_SECURITY_READ_TIMEOUT_MS {
757 None
758 } else {
759 let adjusted_timeout_ms: u64 = (read_timeout_ms >> 1) + (read_timeout_ms & 1);
760 Some(Duration::from_millis(adjusted_timeout_ms))
761 };
762 loop {
763 let len: usize = match Ws::read(
764 stream,
765 &mut temp_buffer,
766 duration_opt,
767 &mut is_client_response,
768 )
769 .await
770 {
771 Ok(Some(len)) => len,
772 Ok(None) => continue,
773 Err(error) => return Err(error),
774 };
775 if len == 0 {
776 return Err(RequestError::IncompleteWebSocketFrame(
777 HttpStatus::BadRequest,
778 ));
779 }
780 dynamic_buffer.extend_from_slice(&temp_buffer[..len]);
781 while let Some((frame, consumed)) = WebSocketFrame::decode_ws_frame(&dynamic_buffer) {
782 is_client_response = true;
783 dynamic_buffer.drain(0..consumed);
784 match frame.get_opcode() {
785 WebSocketOpcode::Close => {
786 return Err(RequestError::ClientClosedConnection(HttpStatus::BadRequest));
787 }
788 WebSocketOpcode::Ping | WebSocketOpcode::Pong => continue,
789 WebSocketOpcode::Text | WebSocketOpcode::Binary => {
790 match Ws::parse_frame(self, &frame, &mut full_frame) {
791 Ok(Some(result)) => return Ok(result),
792 Ok(None) => continue,
793 Err(error) => return Err(error),
794 }
795 }
796 _ => {
797 return Err(RequestError::WebSocketOpcodeUnsupported(
798 HttpStatus::NotImplemented,
799 ));
800 }
801 }
802 }
803 }
804 }
805
806 /// Tries to get a query parameter value by key.
807 ///
808 /// The key type must implement AsRef<str> conversion.
809 ///
810 /// # Arguments
811 ///
812 /// - `AsRef<str>` - The query parameter key (implements AsRef<str>).
813 ///
814 /// # Returns
815 ///
816 /// - `Option<RequestQuerysValue>` - The parameter value if exists.
817 #[inline(always)]
818 pub fn try_get_query<K>(&self, key: K) -> Option<RequestQuerysValue>
819 where
820 K: AsRef<str>,
821 {
822 self.querys.get(key.as_ref()).cloned()
823 }
824
825 /// Gets a query parameter value by key.
826 ///
827 /// The key type must implement AsRef<str> conversion.
828 ///
829 /// # Arguments
830 ///
831 /// - `AsRef<str>` - The query parameter key (implements AsRef<str>).
832 ///
833 /// # Returns
834 ///
835 /// - `RequestQuerysValue` - The parameter value if exists.
836 ///
837 /// # Panics
838 ///
839 /// This function will panic if the query parameter key is not found.
840 #[inline(always)]
841 pub fn get_query<K>(&self, key: K) -> RequestQuerysValue
842 where
843 K: AsRef<str>,
844 {
845 self.try_get_query(key).unwrap()
846 }
847
848 /// Tries to retrieve the value of a request header by its key.
849 ///
850 /// # Arguments
851 ///
852 /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
853 ///
854 /// # Returns
855 ///
856 /// - `Option<RequestHeadersValue>` - The optional header values.
857 #[inline(always)]
858 pub fn try_get_header<K>(&self, key: K) -> Option<RequestHeadersValue>
859 where
860 K: AsRef<str>,
861 {
862 self.headers.get(key.as_ref()).cloned()
863 }
864
865 /// Retrieves the value of a request header by its key.
866 ///
867 /// # Arguments
868 ///
869 /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
870 ///
871 /// # Returns
872 ///
873 /// - `RequestHeadersValue` - The optional header values.
874 ///
875 /// # Panics
876 ///
877 /// This function will panic if the header key is not found.
878 #[inline(always)]
879 pub fn get_header<K>(&self, key: K) -> RequestHeadersValue
880 where
881 K: AsRef<str>,
882 {
883 self.try_get_header(key).unwrap()
884 }
885
886 /// Tries to retrieve the first value of a request header by its key.
887 ///
888 /// # Arguments
889 ///
890 /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
891 ///
892 /// # Returns
893 ///
894 /// - `Option<RequestHeadersValueItem>` - The first header value if exists.
895 #[inline(always)]
896 pub fn try_get_header_front<K>(&self, key: K) -> Option<RequestHeadersValueItem>
897 where
898 K: AsRef<str>,
899 {
900 self.headers
901 .get(key.as_ref())
902 .and_then(|values| values.front().cloned())
903 }
904
905 /// Retrieves the first value of a request header by its key.
906 ///
907 /// # Arguments
908 ///
909 /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
910 ///
911 /// # Returns
912 ///
913 /// - `RequestHeadersValueItem` - The first header value if exists.
914 ///
915 /// # Panics
916 ///
917 /// This function will panic if the header key is not found.
918 #[inline(always)]
919 pub fn get_header_front<K>(&self, key: K) -> RequestHeadersValueItem
920 where
921 K: AsRef<str>,
922 {
923 self.try_get_header_front(key).unwrap()
924 }
925
926 /// Tries to retrieve the last value of a request header by its key.
927 ///
928 /// # Arguments
929 ///
930 /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
931 ///
932 /// # Returns
933 ///
934 /// - `Option<RequestHeadersValueItem>` - The last header value if exists.
935 #[inline(always)]
936 pub fn try_get_header_back<K>(&self, key: K) -> Option<RequestHeadersValueItem>
937 where
938 K: AsRef<str>,
939 {
940 self.headers
941 .get(key.as_ref())
942 .and_then(|values| values.back().cloned())
943 }
944
945 /// Retrieves the last value of a request header by its key.
946 ///
947 /// # Arguments
948 ///
949 /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
950 ///
951 /// # Returns
952 ///
953 /// - `RequestHeadersValueItem` - The last header value if exists.
954 ///
955 /// # Panics
956 ///
957 /// This function will panic if the header key is not found.
958 #[inline(always)]
959 pub fn get_header_back<K>(&self, key: K) -> RequestHeadersValueItem
960 where
961 K: AsRef<str>,
962 {
963 self.try_get_header_back(key).unwrap()
964 }
965
966 /// Tries to retrieve the number of values for a specific header.
967 ///
968 /// # Arguments
969 ///
970 /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
971 ///
972 /// # Returns
973 ///
974 /// - `Option<usize>` - The count of values for the header if exists.
975 #[inline(always)]
976 pub fn try_get_header_size<K>(&self, key: K) -> Option<usize>
977 where
978 K: AsRef<str>,
979 {
980 self.headers.get(key.as_ref()).map(|values| values.len())
981 }
982
983 /// Retrieves the number of values for a specific header.
984 ///
985 /// # Arguments
986 ///
987 /// - `AsRef<str>` - The header's key (must implement AsRef<str>).
988 ///
989 /// # Returns
990 ///
991 /// - `usize` - The count of values for the header.
992 ///
993 /// # Panics
994 ///
995 /// This function will panic if the header key is not found.
996 #[inline(always)]
997 pub fn get_header_size<K>(&self, key: K) -> usize
998 where
999 K: AsRef<str>,
1000 {
1001 self.try_get_header_size(key).unwrap()
1002 }
1003
1004 /// Retrieves the total number of header values across all headers.
1005 ///
1006 /// # Returns
1007 ///
1008 /// - `usize` - The total count of all header values.
1009 #[inline(always)]
1010 pub fn get_headers_values_size(&self) -> usize {
1011 self.headers.values().map(|values| values.len()).sum()
1012 }
1013
1014 /// Retrieves the number of unique headers.
1015 ///
1016 /// # Returns
1017 ///
1018 /// - `usize` - The count of unique header keys.
1019 #[inline(always)]
1020 pub fn get_headers_size(&self) -> usize {
1021 self.headers.len()
1022 }
1023
1024 /// Checks if a specific header exists.
1025 ///
1026 /// # Arguments
1027 ///
1028 /// - `AsRef<str>` - The header key to check (must implement AsRef<str>).
1029 ///
1030 /// # Returns
1031 ///
1032 /// - `bool` - Whether the header exists.
1033 #[inline(always)]
1034 pub fn has_header<K>(&self, key: K) -> bool
1035 where
1036 K: AsRef<str>,
1037 {
1038 self.headers.contains_key(key.as_ref())
1039 }
1040
1041 /// Checks if a header contains a specific value.
1042 ///
1043 /// # Arguments
1044 ///
1045 /// - `AsRef<str>` - The header key to check (must implement AsRef<str>).
1046 /// - `AsRef<str>` - The value to search for (must implement AsRef<str>).
1047 ///
1048 /// # Returns
1049 ///
1050 /// - `bool` - Whether the header contains the value.
1051 #[inline(always)]
1052 pub fn has_header_value<K, V>(&self, key: K, value: V) -> bool
1053 where
1054 K: AsRef<str>,
1055 V: AsRef<str>,
1056 {
1057 if let Some(values) = self.headers.get(key.as_ref()) {
1058 values.iter().any(|v| v == value.as_ref())
1059 } else {
1060 false
1061 }
1062 }
1063
1064 /// Tries to parse cookies from the `Cookie` header.
1065 ///
1066 /// This method retrieves the `Cookie` header value and parses it into
1067 /// a collection of key-value pairs representing the cookies.
1068 ///
1069 /// # Returns
1070 ///
1071 /// - `Option<Cookies>` - The parsed cookies if the header exists, otherwise `None`.
1072 #[inline(always)]
1073 pub fn try_get_cookies(&self) -> Option<Cookies> {
1074 self.try_get_header_back(COOKIE)
1075 .map(|cookie_header: String| Cookie::parse(cookie_header))
1076 }
1077
1078 /// Parses cookies from the `Cookie` header.
1079 ///
1080 /// This method retrieves the `Cookie` header value and parses it into
1081 /// a collection of key-value pairs representing the cookies.
1082 ///
1083 /// # Returns
1084 ///
1085 /// - `Cookies` - The parsed cookies.
1086 ///
1087 /// # Panics
1088 ///
1089 /// This function will panic if the `Cookie` header is not found.
1090 #[inline(always)]
1091 pub fn get_cookies(&self) -> Cookies {
1092 self.try_get_cookies().unwrap()
1093 }
1094
1095 /// Tries to get a cookie value by its key.
1096 ///
1097 /// This method first parses the cookies from the `Cookie` header,
1098 /// then attempts to retrieve the value for the specified key.
1099 ///
1100 /// # Arguments
1101 ///
1102 /// - `AsRef<str>` - The cookie key (implements AsRef<str>).
1103 ///
1104 /// # Returns
1105 ///
1106 /// - `Option<CookieValue>` - The cookie value if exists.
1107 #[inline(always)]
1108 pub fn try_get_cookie<K>(&self, key: K) -> Option<CookieValue>
1109 where
1110 K: AsRef<str>,
1111 {
1112 self.try_get_cookies()
1113 .and_then(|cookies: Cookies| cookies.get(key.as_ref()).cloned())
1114 }
1115
1116 /// Gets a cookie value by its key.
1117 ///
1118 /// This method first parses the cookies from the `Cookie` header,
1119 /// then retrieves the value for the specified key.
1120 ///
1121 /// # Arguments
1122 ///
1123 /// - `AsRef<str>` - The cookie key (implements AsRef<str>).
1124 ///
1125 /// # Returns
1126 ///
1127 /// - `CookieValue` - The cookie value.
1128 ///
1129 /// # Panics
1130 ///
1131 /// This function will panic if the `Cookie` header is not found
1132 /// or the cookie key does not exist.
1133 #[inline(always)]
1134 pub fn get_cookie<K>(&self, key: K) -> CookieValue
1135 where
1136 K: AsRef<str>,
1137 {
1138 self.try_get_cookie(key).unwrap()
1139 }
1140
1141 /// Retrieves the upgrade type from the request headers.
1142 ///
1143 /// This method looks for the `UPGRADE` header and attempts to parse its value
1144 /// as_ref an `UpgradeType`. If the header is missing or the value is invalid,
1145 /// it returns the default `UpgradeType`.
1146 ///
1147 /// # Returns
1148 ///
1149 /// - `UpgradeType` - The parsed upgrade type.
1150 #[inline(always)]
1151 pub fn get_upgrade_type(&self) -> UpgradeType {
1152 self.try_get_header_back(UPGRADE)
1153 .and_then(|data| data.parse::<UpgradeType>().ok())
1154 .unwrap_or_default()
1155 }
1156
1157 /// Retrieves the body content of the request as a UTF-8 encoded string.
1158 ///
1159 /// This method uses `String::from_utf8_lossy` to convert the byte slice returned by `self.get_body()` as a string.
1160 /// If the byte slice contains invalid UTF-8 sequences, they will be replaced with the Unicode replacement character ().
1161 ///
1162 /// # Returns
1163 ///
1164 /// - `String` - The body content as a string.
1165 #[inline(always)]
1166 pub fn get_body_string(&self) -> String {
1167 String::from_utf8_lossy(self.get_body()).into_owned()
1168 }
1169
1170 /// Deserializes the body content of the request as_ref a specified type `T`.
1171 ///
1172 /// This method first retrieves the body content as a byte slice using `self.get_body()`.
1173 /// It then attempts to deserialize the byte slice as_ref the specified type `T` using `json_from_slice`.
1174 ///
1175 /// # Arguments
1176 ///
1177 /// - `DeserializeOwned` - The target type to deserialize as_ref (must implement DeserializeOwned).
1178 ///
1179 /// # Returns
1180 ///
1181 /// - `Result<T, serde_json::Error>` - The deserialization result.
1182 #[inline(always)]
1183 pub fn try_get_body_json<T>(&self) -> Result<T, serde_json::Error>
1184 where
1185 T: DeserializeOwned,
1186 {
1187 serde_json::from_slice(self.get_body())
1188 }
1189
1190 /// Deserializes the body content of the request as_ref a specified type `T`.
1191 ///
1192 /// This method first retrieves the body content as a byte slice using `self.get_body()`.
1193 /// It then attempts to deserialize the byte slice as_ref the specified type `T` using `json_from_slice`.
1194 ///
1195 /// # Arguments
1196 ///
1197 /// - `DeserializeOwned` - The target type to deserialize as_ref (must implement DeserializeOwned).
1198 ///
1199 /// # Returns
1200 ///
1201 /// - `T` - The deserialized body content.
1202 ///
1203 /// # Panics
1204 ///
1205 /// This function will panic if the deserialization fails.
1206 #[inline(always)]
1207 pub fn get_body_json<T>(&self) -> T
1208 where
1209 T: DeserializeOwned,
1210 {
1211 self.try_get_body_json().unwrap()
1212 }
1213
1214 /// Checks whether the request method is GET.
1215 ///
1216 /// # Returns
1217 ///
1218 /// - `bool` - Whether the method is GET.
1219 #[inline(always)]
1220 pub fn is_get_method(&self) -> bool {
1221 self.get_method().is_get()
1222 }
1223
1224 /// Checks whether the request method is POST.
1225 ///
1226 /// # Returns
1227 ///
1228 /// - `bool` - Whether the method is POST.
1229 #[inline(always)]
1230 pub fn is_post_method(&self) -> bool {
1231 self.get_method().is_post()
1232 }
1233
1234 /// Checks whether the request method is PUT.
1235 ///
1236 /// # Returns
1237 ///
1238 /// - `bool` - Whether the method is PUT.
1239 #[inline(always)]
1240 pub fn is_put_method(&self) -> bool {
1241 self.get_method().is_put()
1242 }
1243
1244 /// Checks whether the request method is DELETE.
1245 ///
1246 /// # Returns
1247 ///
1248 /// - `bool` - Whether the method is DELETE.
1249 #[inline(always)]
1250 pub fn is_delete_method(&self) -> bool {
1251 self.get_method().is_delete()
1252 }
1253
1254 /// Checks whether the request method is PATCH.
1255 ///
1256 /// # Returns
1257 ///
1258 /// - `bool` - Whether the method is PATCH.
1259 #[inline(always)]
1260 pub fn is_patch_method(&self) -> bool {
1261 self.get_method().is_patch()
1262 }
1263
1264 /// Checks whether the request method is HEAD.
1265 ///
1266 /// # Returns
1267 ///
1268 /// - `bool` - Whether the method is HEAD.
1269 #[inline(always)]
1270 pub fn is_head_method(&self) -> bool {
1271 self.get_method().is_head()
1272 }
1273
1274 /// Checks whether the request method is OPTIONS.
1275 ///
1276 /// # Returns
1277 ///
1278 /// - `bool` - Whether the method is OPTIONS.
1279 #[inline(always)]
1280 pub fn is_options_method(&self) -> bool {
1281 self.get_method().is_options()
1282 }
1283
1284 /// Checks whether the request method is CONNECT.
1285 ///
1286 /// # Returns
1287 ///
1288 /// - `bool` - Whether the method is CONNECT.
1289 #[inline(always)]
1290 pub fn is_connect_method(&self) -> bool {
1291 self.get_method().is_connect()
1292 }
1293
1294 /// Checks whether the request method is TRACE.
1295 ///
1296 /// # Returns
1297 ///
1298 /// - `bool` - Whether the method is TRACE.
1299 #[inline(always)]
1300 pub fn is_trace_method(&self) -> bool {
1301 self.get_method().is_trace()
1302 }
1303
1304 /// Checks whether the request method is UNKNOWN.
1305 ///
1306 /// # Returns
1307 ///
1308 /// - `bool` - Whether the method is UNKNOWN.
1309 #[inline(always)]
1310 pub fn is_unknown_method(&self) -> bool {
1311 self.get_method().is_unknown()
1312 }
1313
1314 /// Checks whether the HTTP version is HTTP/0.9.
1315 ///
1316 /// # Returns
1317 ///
1318 /// - `bool` - Whether the version is HTTP/0.9.
1319 #[inline(always)]
1320 pub fn is_http0_9_version(&self) -> bool {
1321 self.get_version().is_http0_9()
1322 }
1323
1324 /// Checks whether the HTTP version is HTTP/1.0.
1325 ///
1326 /// # Returns
1327 ///
1328 /// - `bool` - Whether the version is HTTP/1.0.
1329 #[inline(always)]
1330 pub fn is_http1_0_version(&self) -> bool {
1331 self.get_version().is_http1_0()
1332 }
1333
1334 /// Checks whether the HTTP version is HTTP/1.1.
1335 ///
1336 /// # Returns
1337 ///
1338 /// - `bool` - Whether the version is HTTP/1.1.
1339 #[inline(always)]
1340 pub fn is_http1_1_version(&self) -> bool {
1341 self.get_version().is_http1_1()
1342 }
1343
1344 /// Checks whether the HTTP version is HTTP/2.
1345 ///
1346 /// # Returns
1347 ///
1348 /// - `bool` - Whether the version is HTTP/2.
1349 #[inline(always)]
1350 pub fn is_http2_version(&self) -> bool {
1351 self.get_version().is_http2()
1352 }
1353
1354 /// Checks whether the HTTP version is HTTP/3.
1355 ///
1356 /// # Returns
1357 ///
1358 /// - `bool` - Whether the version is HTTP/3.
1359 #[inline(always)]
1360 pub fn is_http3_version(&self) -> bool {
1361 self.get_version().is_http3()
1362 }
1363
1364 /// Checks if the HTTP version is HTTP/1.1 or higher.
1365 ///
1366 /// # Returns
1367 ///
1368 /// - `bool` - Whether the version is HTTP/1.1 or higher.
1369 #[inline(always)]
1370 pub fn is_http1_1_or_higher_version(&self) -> bool {
1371 self.get_version().is_http1_1_or_higher()
1372 }
1373
1374 /// Checks whether the version belongs to the HTTP family.
1375 ///
1376 /// # Returns
1377 ///
1378 /// - `bool` - Whether the version is HTTP.
1379 #[inline(always)]
1380 pub fn is_http_version(&self) -> bool {
1381 self.get_version().is_http()
1382 }
1383
1384 /// Checks whether the HTTP version is unknown.
1385 ///
1386 /// # Returns
1387 ///
1388 /// - `bool` - Whether the version is unknown.
1389 #[inline(always)]
1390 pub fn is_unknown_version(&self) -> bool {
1391 self.get_version().is_unknown()
1392 }
1393
1394 /// Checks whether the WebSocket upgrade is enabled for this request.
1395 ///
1396 /// This method determines if the `UPGRADE` header indicates a WebSocket connection.
1397 ///
1398 /// # Returns
1399 ///
1400 /// - `bool` - Whether WebSocket upgrade is enabled.
1401 #[inline(always)]
1402 pub fn is_ws_upgrade_type(&self) -> bool {
1403 self.get_upgrade_type().is_ws()
1404 }
1405
1406 /// Checks if the current upgrade type is HTTP/2 cleartext (h2c).
1407 ///
1408 /// # Returns
1409 ///
1410 /// - `bool` - Whether the upgrade type is h2c.
1411 #[inline(always)]
1412 pub fn is_h2c_upgrade_type(&self) -> bool {
1413 self.get_upgrade_type().is_h2c()
1414 }
1415
1416 /// Checks if the current upgrade type is TLS (any version).
1417 ///
1418 /// # Returns
1419 ///
1420 /// - `bool` - Whether the upgrade type is TLS.
1421 #[inline(always)]
1422 pub fn is_tls_upgrade_type(&self) -> bool {
1423 self.get_upgrade_type().is_tls()
1424 }
1425
1426 /// Checks whether the upgrade type is unknown.
1427 ///
1428 /// # Returns
1429 ///
1430 /// - `bool` - Whether the upgrade type is unknown.
1431 #[inline(always)]
1432 pub fn is_unknown_upgrade_type(&self) -> bool {
1433 self.get_upgrade_type().is_unknown()
1434 }
1435
1436 /// Determines if a keep-alive connection should be enabled for this request.
1437 ///
1438 /// This function checks the `Connection` header and the HTTP version to determine
1439 /// if keep-alive should be enabled. The logic is as follows:
1440 ///
1441 /// 1. If the `Connection` header exists:
1442 /// - Returns `true` if the header value is "keep-alive" (case-insensitive).
1443 /// - Returns `false` if the header value is "close" (case-insensitive).
1444 /// 2. If no `Connection` header is present:
1445 /// - Returns `true` if the HTTP version is 1.1 or higher.
1446 /// - Returns `false` otherwise.
1447 ///
1448 /// # Returns
1449 ///
1450 /// - `bool` - Whether keep-alive should be enabled.
1451 #[inline(always)]
1452 pub fn is_enable_keep_alive(&self) -> bool {
1453 if let Some(connection_value) = self.try_get_header_back(CONNECTION) {
1454 if connection_value.eq_ignore_ascii_case(KEEP_ALIVE) {
1455 return true;
1456 } else if connection_value.eq_ignore_ascii_case(CLOSE) {
1457 return self.is_ws_upgrade_type();
1458 }
1459 }
1460 self.is_http1_1_or_higher_version() || self.is_ws_upgrade_type()
1461 }
1462
1463 /// Determines if keep-alive should be disabled for this request.
1464 ///
1465 /// # Returns
1466 ///
1467 /// - `bool` - Whether keep-alive should be disabled.
1468 #[inline(always)]
1469 pub fn is_disable_keep_alive(&self) -> bool {
1470 !self.is_enable_keep_alive()
1471 }
1472}