Skip to main content

nexus_web/rest/
response.rs

1//! REST response — borrows from the ResponseReader's buffer.
2
3use crate::http::ResponseReader;
4
5/// HTTP response. Borrows from the connection's ResponseReader.
6///
7/// Must be dropped before the next request on the same connection
8/// (same pattern as WebSocket `Message<'_>`).
9pub struct RestResponse<'a> {
10    pub(crate) status: u16,
11    pub(crate) body_len: usize,
12    pub(crate) resp_reader: &'a ResponseReader,
13    /// Decoded body for chunked responses. None = use reader remainder.
14    pub(crate) chunked_body: Option<Vec<u8>>,
15}
16
17impl<'a> RestResponse<'a> {
18    /// Create a response from parsed data (Content-Length delimited).
19    ///
20    /// Typically called by transport layers after reading and parsing
21    /// the response.
22    pub fn new(status: u16, body_len: usize, resp_reader: &'a ResponseReader) -> Self {
23        Self {
24            status,
25            body_len,
26            resp_reader,
27            chunked_body: None,
28        }
29    }
30
31    /// Create a response with a decoded chunked body.
32    pub fn new_chunked(status: u16, body: Vec<u8>, resp_reader: &'a ResponseReader) -> Self {
33        let body_len = body.len();
34        Self {
35            status,
36            body_len,
37            resp_reader,
38            chunked_body: Some(body),
39        }
40    }
41
42    /// HTTP status code.
43    pub fn status(&self) -> u16 {
44        self.status
45    }
46
47    /// Look up a response header by name (case-insensitive).
48    pub fn header(&self, name: &str) -> Option<&str> {
49        self.resp_reader.header(name)
50    }
51
52    /// Response body as bytes.
53    pub fn body(&self) -> &[u8] {
54        if let Some(ref chunked) = self.chunked_body {
55            return chunked;
56        }
57        let remainder = self.resp_reader.remainder();
58        &remainder[..self.body_len.min(remainder.len())]
59    }
60
61    /// Response body as a UTF-8 string.
62    pub fn body_str(&self) -> Result<&str, std::str::Utf8Error> {
63        std::str::from_utf8(self.body())
64    }
65
66    /// Response body length (from Content-Length header).
67    pub fn body_len(&self) -> usize {
68        self.body_len
69    }
70
71    /// Copy the response body into `bytes::Bytes`.
72    ///
73    /// Allocates once — copies the body slice into a `Bytes` handle
74    /// that is `Send + Clone` for cross-thread passing.
75    ///
76    /// ```ignore
77    /// let resp = conn.send(req, &mut reader)?;
78    /// let body: Bytes = resp.body_to_bytes();
79    /// tx.send(body)?;
80    /// ```
81    #[cfg(feature = "bytes")]
82    pub fn body_to_bytes(&self) -> bytes::Bytes {
83        bytes::Bytes::copy_from_slice(self.body())
84    }
85
86    /// Number of response headers.
87    pub fn header_count(&self) -> usize {
88        self.resp_reader.header_count()
89    }
90}
91
92impl std::fmt::Debug for RestResponse<'_> {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        f.debug_struct("RestResponse")
95            .field("status", &self.status)
96            .field("body_len", &self.body_len)
97            .finish()
98    }
99}