http_type/response/
impl.rs

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