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: DashMap::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
162        for header in headers.iter() {
163            let key: &str = header.key();
164            let value: &str = header.value();
165            if key.eq_ignore_ascii_case(CONTENT_LENGTH) {
166                continue;
167            } else if key.eq_ignore_ascii_case(CONTENT_ENCODING) {
168                compress_type_opt = Some(value.parse::<Compress>().unwrap_or_default());
169            } else if key.eq_ignore_ascii_case(CONNECTION) {
170                connection_opt = Some(value.to_owned());
171            } else if key.eq_ignore_ascii_case(CONTENT_TYPE) {
172                content_type_opt = Some(value.to_owned());
173                if value.eq_ignore_ascii_case(TEXT_EVENT_STREAM) {
174                    unset_content_length = true;
175                }
176            }
177            Self::push_header(&mut response_string, &key, value);
178        }
179        if connection_opt.is_none() {
180            Self::push_header(&mut response_string, CONNECTION, CONNECTION_KEEP_ALIVE);
181        }
182        if content_type_opt.is_none() {
183            Self::push_header(
184                &mut response_string,
185                CONTENT_TYPE,
186                &format!("{}{}{}", TEXT_HTML, SEMICOLON_SPACE, CHARSET_UTF_8),
187            );
188        }
189        let mut body: Cow<Vec<u8>> = Cow::Borrowed(self.get_body());
190        if !unset_content_length {
191            if let Some(compress_type) = compress_type_opt {
192                if !compress_type.is_unknown() {
193                    let tmp_body: Cow<'_, Vec<u8>> =
194                        compress_type.encode(&body, DEFAULT_BUFFER_SIZE);
195                    body = Cow::Owned(tmp_body.into_owned());
196                }
197            }
198            let len_string: String = body.len().to_string();
199            Self::push_header(&mut response_string, CONTENT_LENGTH, &len_string);
200        }
201        response_string.push_str(HTTP_BR);
202        let mut response_bytes: Vec<u8> = response_string.into_bytes();
203        response_bytes.extend_from_slice(&body);
204        response_bytes
205    }
206
207    /// Sends the HTTP response body over a TCP stream.
208    ///
209    /// # Parameters
210    /// - `stream`: A mutable reference to the `TcpStream` to send the response.
211    /// - `is_websocket`: Is websocket
212    ///
213    /// # Returns
214    /// - `Ok`: If the response body is successfully sent.
215    /// - `Err`: If an error occurs during sending.
216    #[inline]
217    pub async fn send_body(
218        &mut self,
219        stream_lock: &ArcRwLockStream,
220        is_websocket: bool,
221    ) -> ResponseResult {
222        let body: &ResponseBody = self.get_body();
223        stream_lock.send_body(body, is_websocket).await
224    }
225
226    /// Sends the HTTP response over a TCP stream.
227    ///
228    /// # Parameters
229    /// - `stream`: A mutable reference to the `TcpStream` to send the response.
230    ///
231    /// # Returns
232    /// - `Ok`: If the response is successfully sent.
233    /// - `Err`: If an error occurs during sending.
234    #[inline]
235    pub async fn send(&mut self, stream_lock: &ArcRwLockStream) -> ResponseResult {
236        let data: Vec<u8> = self.build();
237        stream_lock.send(&data).await
238    }
239
240    /// Flush the TCP stream.
241    ///
242    /// - `stream_lock`: A reference to an `ArcRwLockStream` that manages the TCP stream.
243    ///
244    /// - Returns: A `ResponseResult` indicating success or failure.
245    #[inline]
246    pub async fn flush(&mut self, stream_lock: &ArcRwLockStream) -> ResponseResult {
247        stream_lock.flush().await
248    }
249
250    /// Closes the stream after sending the response.
251    ///
252    /// This function is responsible for:
253    /// - Building the response using the `build()` method.
254    /// - Setting the response using the `set_response()` method.
255    /// - Shutting down the write half of the TCP stream to indicate no more data will be sent.
256    ///
257    /// # Parameters
258    /// - `stream`: A reference to the `TcpStream` that will be closed after sending the response.
259    ///
260    /// # Returns
261    /// - `ResponseResult`: The result of the operation, indicating whether the closure was successful or if an error occurred.
262    #[inline]
263    pub async fn close(&mut self, stream_lock: &ArcRwLockStream) -> ResponseResult {
264        stream_lock.close().await
265    }
266
267    /// Converts the response to a formatted string representation.
268    ///
269    /// - Returns: A `String` containing formatted response details.
270    #[inline]
271    pub fn get_string(&self) -> String {
272        let body: &Vec<u8> = self.get_body();
273        format!(
274            "[Response] => [Version]: {}; [Status Code]: {}; [Reason]: {}; [Headers]: {:?}; [Body]: {};",
275            self.get_version(),
276            self.get_status_code(),
277            self.get_reason_phrase(),
278            self.get_headers(),
279            body_to_string(body),
280        )
281    }
282}