http_type/response/
impl.rs

1use crate::*;
2
3impl Default for Response {
4    #[inline]
5    fn default() -> Self {
6        Self::new()
7    }
8}
9
10impl Response {
11    /// Creates a new instance of `Response`.
12    ///
13    /// # Returns
14    /// - An initialized `Response` with default values.
15    #[inline]
16    pub fn new() -> Self {
17        Response {
18            version: HTTP_VERSION_1_1.to_owned(),
19            status_code: 200,
20            reason_phrase: EMPTY_STR.to_owned(),
21            headers: ResponseHeaders::new(),
22            body: Vec::new(),
23        }
24    }
25
26    /// Retrieves the value of a response header by its key.
27    ///
28    /// # Parameters
29    /// - `key`: The header's key, which can be of any type that implements `Into<ResponseHeadersKey>`.
30    ///
31    /// # Returns
32    /// - `Option<ResponseHeadersValue>`: Returns `Some(value)` if the key exists in the response headers,
33    ///   or `None` if the key does not exist.
34    #[inline]
35    pub fn get_header<K>(&self, key: K) -> Option<ResponseHeadersValue>
36    where
37        K: Into<ResponseHeadersKey>,
38    {
39        self.headers
40            .get(&key.into())
41            .and_then(|data| Some(data.clone()))
42    }
43
44    /// Adds a header to the response.
45    ///
46    /// This function inserts a key-value pair into the response headers.
47    /// The key and value are converted into `ResponseHeadersKey`, allowing for efficient handling of both owned and borrowed string data.
48    ///
49    /// # Parameters
50    /// - `key`: The header key, which will be converted into a `ResponseHeadersKey`.
51    /// - `value`: The value of the header, which will be converted into a `ResponseHeadersValue`.
52    ///
53    /// # Returns
54    /// - Returns a mutable reference to the current instance (`&mut Self`), allowing for method chaining.
55    #[inline]
56    pub fn set_header<K, V>(&mut self, key: K, value: V) -> &mut Self
57    where
58        K: Into<ResponseHeadersKey>,
59        V: Into<ResponseHeadersValue>,
60    {
61        self.headers.insert(key.into(), value.into());
62        self
63    }
64
65    /// Set the body of the response.
66    ///
67    /// This method allows you to set the body of the response by converting the provided
68    /// value into a `ResponseBody` type. The `body` is updated with the converted value,
69    /// and the method returns a mutable reference to the current instance for method chaining.
70    ///
71    /// # Parameters
72    /// - `body`: The body of the response to be set. It can be any type that can be converted
73    ///   into a `ResponseBody` using the `Into` trait.
74    ///
75    /// # Return Value
76    /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
77    /// Set the body of the response.
78    ///
79    /// This method allows you to set the body of the response by converting the provided
80    /// value into a `ResponseBody` type. The `body` is updated with the converted value,
81    /// and the method returns a mutable reference to the current instance for method chaining.
82    ///
83    /// # Parameters
84    /// - `body`: The body of the response to be set. It can be any type that can be converted
85    ///   into a `ResponseBody` using the `Into` trait.
86    ///
87    /// # Return Value
88    /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
89    #[inline]
90    pub fn set_body<T: Into<ResponseBody>>(&mut self, body: T) -> &mut Self {
91        self.body = body.into();
92        self
93    }
94
95    /// Set the reason phrase of the response.
96    ///
97    /// This method allows you to set the reason phrase of the response by converting the
98    /// provided value into a `ResponseReasonPhrase` type. The `reason_phrase` is updated
99    /// with the converted value, and the method returns a mutable reference to the current
100    /// instance for method chaining.
101    ///
102    /// # Parameters
103    /// - `reason_phrase`: The reason phrase to be set for the response. It can be any type
104    ///   that can be converted into a `ResponseReasonPhrase` using the `Into` trait.
105    ///
106    /// # Return Value
107    /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
108    #[inline]
109    pub fn set_reason_phrase<T: Into<ResponseReasonPhrase>>(
110        &mut self,
111        reason_phrase: T,
112    ) -> &mut Self {
113        self.reason_phrase = reason_phrase.into();
114        self
115    }
116
117    /// Pushes a header with a key and value into the response string.
118    ///
119    /// # Parameters
120    /// - `response_string`: A mutable reference to the string where the header will be added.
121    /// - `key`: The header key as a string slice (`&str`).
122    /// - `value`: The header value as a string slice (`&str`).
123    #[inline]
124    pub(super) fn push_header(response_string: &mut String, key: &str, value: &str) {
125        response_string.push_str(&format!("{}{}{}{}", key, COLON_SPACE, value, HTTP_BR));
126    }
127
128    /// Pushes the first line of an HTTP response (version, status code, and reason phrase) into the response string.
129    /// This corresponds to the status line of the HTTP response.
130    ///
131    /// # Parameters
132    /// - `response_string`: A mutable reference to the string where the first line will be added.
133    #[inline]
134    pub(super) fn push_http_response_first_line(&self, response_string: &mut String) {
135        response_string.push_str(&format!(
136            "{}{}{}{}{}{}",
137            self.get_version(),
138            SPACE,
139            self.get_status_code(),
140            SPACE,
141            self.get_reason_phrase(),
142            HTTP_BR
143        ));
144    }
145
146    /// Builds the full HTTP response as a byte vector.
147    /// # Returns
148    /// - `ResponseData`: response data
149    #[inline]
150    pub(super) fn build(&mut self) -> ResponseData {
151        if self.reason_phrase.is_empty() {
152            self.set_reason_phrase(HttpStatus::phrase(*self.get_status_code()));
153        }
154        let mut response_string: String = String::new();
155        self.push_http_response_first_line(&mut response_string);
156        let mut compress_type_opt: Option<Compress> = None;
157        let mut connection_opt: Option<String> = None;
158        let mut content_type_opt: Option<String> = None;
159        let headers: &ResponseHeaders = self.get_headers();
160        let mut unset_content_length: bool = false;
161        for (key, value) in headers.iter() {
162            if key.eq_ignore_ascii_case(CONTENT_LENGTH) {
163                continue;
164            } else if key.eq_ignore_ascii_case(CONTENT_ENCODING) {
165                compress_type_opt = Some(value.parse::<Compress>().unwrap_or_default());
166            } else if key.eq_ignore_ascii_case(CONNECTION) {
167                connection_opt = Some(value.to_owned());
168            } else if key.eq_ignore_ascii_case(CONTENT_TYPE) {
169                content_type_opt = Some(value.to_owned());
170                if value.eq_ignore_ascii_case(TEXT_EVENT_STREAM) {
171                    unset_content_length = true;
172                }
173            }
174            Self::push_header(&mut response_string, &key, value);
175        }
176        if connection_opt.is_none() {
177            Self::push_header(&mut response_string, CONNECTION, CONNECTION_KEEP_ALIVE);
178        }
179        if content_type_opt.is_none() {
180            Self::push_header(
181                &mut response_string,
182                CONTENT_TYPE,
183                &format!("{}{}{}", TEXT_HTML, SEMICOLON_SPACE, CHARSET_UTF_8),
184            );
185        }
186        let mut body: Cow<Vec<u8>> = Cow::Borrowed(self.get_body());
187        if !unset_content_length {
188            if let Some(compress_type) = compress_type_opt {
189                if !compress_type.is_unknown() {
190                    let tmp_body: Cow<'_, Vec<u8>> =
191                        compress_type.encode(&body, DEFAULT_BUFFER_SIZE);
192                    body = Cow::Owned(tmp_body.into_owned());
193                }
194            }
195            let len_string: String = body.len().to_string();
196            Self::push_header(&mut response_string, CONTENT_LENGTH, &len_string);
197        }
198        response_string.push_str(HTTP_BR);
199        let mut response_bytes: Vec<u8> = response_string.into_bytes();
200        response_bytes.extend_from_slice(&body);
201        response_bytes
202    }
203
204    /// Sends the HTTP response body over a TCP stream.
205    ///
206    /// # Parameters
207    /// - `stream`: A mutable reference to the `TcpStream` to send the response.
208    /// - `is_websocket`: Is websocket
209    ///
210    /// # Returns
211    /// - `Ok`: If the response body is successfully sent.
212    /// - `Err`: If an error occurs during sending.
213    #[inline]
214    pub async fn send_body(
215        &mut self,
216        stream_lock: &ArcRwLockStream,
217        is_websocket: bool,
218    ) -> ResponseResult {
219        let body: &ResponseBody = self.get_body();
220        stream_lock.send_body(body, is_websocket).await
221    }
222
223    /// Sends the HTTP response over a TCP stream.
224    ///
225    /// # Parameters
226    /// - `stream`: A mutable reference to the `TcpStream` to send the response.
227    ///
228    /// # Returns
229    /// - `Ok`: If the response is successfully sent.
230    /// - `Err`: If an error occurs during sending.
231    #[inline]
232    pub async fn send(&mut self, stream_lock: &ArcRwLockStream) -> ResponseResult {
233        let data: Vec<u8> = self.build();
234        stream_lock.send(&data).await
235    }
236
237    /// Flush the TCP stream.
238    ///
239    /// - `stream_lock`: A reference to an `ArcRwLockStream` that manages the TCP stream.
240    ///
241    /// - Returns: A `ResponseResult` indicating success or failure.
242    #[inline]
243    pub async fn flush(&mut self, stream_lock: &ArcRwLockStream) -> ResponseResult {
244        stream_lock.flush().await
245    }
246
247    /// Closes the stream after sending the response.
248    ///
249    /// This function is responsible for:
250    /// - Building the response using the `build()` method.
251    /// - Setting the response using the `set_response()` method.
252    /// - Shutting down the write half of the TCP stream to indicate no more data will be sent.
253    ///
254    /// # Parameters
255    /// - `stream`: A reference to the `TcpStream` that will be closed after sending the response.
256    ///
257    /// # Returns
258    /// - `ResponseResult`: The result of the operation, indicating whether the closure was successful or if an error occurred.
259    #[inline]
260    pub async fn close(&mut self, stream_lock: &ArcRwLockStream) -> ResponseResult {
261        stream_lock.close().await
262    }
263
264    /// Converts the response to a formatted string representation.
265    ///
266    /// - Returns: A `String` containing formatted response details.
267    #[inline]
268    pub fn get_string(&self) -> String {
269        let body: &Vec<u8> = self.get_body();
270        format!(
271            "[Response] => [Version]: {}; [Status Code]: {}; [Reason]: {}; [Headers]: {:?}; [Body]: {};",
272            self.get_version(),
273            self.get_status_code(),
274            self.get_reason_phrase(),
275            self.get_headers(),
276            body_to_string(body),
277        )
278    }
279}