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_xx_hash3_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    /// Retrieves the body content of the object as a UTF-8 encoded string.
42    ///
43    /// This method uses `String::from_utf8_lossy` to convert the byte slice returned by `self.get_body()` into a string.
44    /// If the byte slice contains invalid UTF-8 sequences, they will be replaced with the Unicode replacement character (�).
45    ///
46    /// # Returns
47    /// A `String` containing the body content.
48    pub fn get_body_string(&self) -> String {
49        String::from_utf8_lossy(self.get_body()).into_owned()
50    }
51
52    /// Deserializes the body content of the object into a specified type `T`.
53    ///
54    /// This method first retrieves the body content as a UTF-8 encoded string using `self.get_body()`.
55    /// It then attempts to deserialize the string into the specified type `T` using `serde_json::from_str`.
56    ///
57    /// # Type Parameters
58    /// - `T`: The target type to deserialize into. It must implement the `DeserializeOwned` trait.
59    ///
60    /// # Returns
61    /// - `Ok(T)`: The deserialized object of type `T` if the deserialization is successful.
62    /// - `Err(serde_json::Error)`: An error if the deserialization fails (e.g., invalid JSON format or type mismatch).
63    pub fn get_body_json<T>(&self) -> ResultSerdeJsonError<T>
64    where
65        T: DeserializeOwned,
66    {
67        serde_json::from_slice(self.get_body())
68    }
69
70    /// Adds a header to the response.
71    ///
72    /// This function inserts a key-value pair into the response headers.
73    /// The key and value are converted into `ResponseHeadersKey`, allowing for efficient handling of both owned and borrowed string data.
74    ///
75    /// # Parameters
76    /// - `key`: The header key, which will be converted into a `ResponseHeadersKey`.
77    /// - `value`: The value of the header, which will be converted into a `ResponseHeadersValue`.
78    ///
79    /// # Returns
80    /// - Returns a mutable reference to the current instance (`&mut Self`), allowing for method chaining.
81    pub fn set_header<K, V>(&mut self, key: K, value: V) -> &mut Self
82    where
83        K: Into<ResponseHeadersKey>,
84        V: Into<ResponseHeadersValue>,
85    {
86        self.headers.insert(key.into(), value.into());
87        self
88    }
89
90    /// Set the body of the response.
91    ///
92    /// This method allows you to set the body of the response by converting the provided
93    /// value into a `ResponseBody` type. The `body` is updated with the converted value,
94    /// and the method returns a mutable reference to the current instance for method chaining.
95    ///
96    /// # Parameters
97    /// - `body`: The body of the response to be set. It can be any type that can be converted
98    ///   into a `ResponseBody` using the `Into` trait.
99    ///
100    /// # Return Value
101    /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
102    /// Set the body of the response.
103    ///
104    /// This method allows you to set the body of the response by converting the provided
105    /// value into a `ResponseBody` type. The `body` is updated with the converted value,
106    /// and the method returns a mutable reference to the current instance for method chaining.
107    ///
108    /// # Parameters
109    /// - `body`: The body of the response to be set. It can be any type that can be converted
110    ///   into a `ResponseBody` using the `Into` trait.
111    ///
112    /// # Return Value
113    /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
114    pub fn set_body<T: Into<ResponseBody>>(&mut self, body: T) -> &mut Self {
115        self.body = body.into();
116        self
117    }
118
119    /// Set the reason phrase of the response.
120    ///
121    /// This method allows you to set the reason phrase of the response by converting the
122    /// provided value into a `ResponseReasonPhrase` type. The `reason_phrase` is updated
123    /// with the converted value, and the method returns a mutable reference to the current
124    /// instance for method chaining.
125    ///
126    /// # Parameters
127    /// - `reason_phrase`: The reason phrase to be set for the response. It can be any type
128    ///   that can be converted into a `ResponseReasonPhrase` using the `Into` trait.
129    ///
130    /// # Return Value
131    /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
132    pub fn set_reason_phrase<T: Into<ResponseReasonPhrase>>(
133        &mut self,
134        reason_phrase: T,
135    ) -> &mut Self {
136        self.reason_phrase = reason_phrase.into();
137        self
138    }
139
140    /// Pushes a header with a key and value into the response string.
141    ///
142    /// # Parameters
143    /// - `response_string`: A mutable reference to the string where the header will be added.
144    /// - `key`: The header key as a string slice (`&str`).
145    /// - `value`: The header value as a string slice (`&str`).
146    pub(super) fn push_header(response_string: &mut String, key: &str, value: &str) {
147        response_string.push_str(&format!("{}{}{}{}", key, COLON_SPACE, value, HTTP_BR));
148    }
149
150    /// Pushes the first line of an HTTP response (version, status code, and reason phrase) into the response string.
151    /// This corresponds to the status line of the HTTP response.
152    ///
153    /// # Parameters
154    /// - `response_string`: A mutable reference to the string where the first line will be added.
155    pub(super) fn push_http_response_first_line(&self, response_string: &mut String) {
156        response_string.push_str(&format!(
157            "{}{}{}{}{}{}",
158            self.get_version(),
159            SPACE,
160            self.get_status_code(),
161            SPACE,
162            self.get_reason_phrase(),
163            HTTP_BR
164        ));
165    }
166
167    /// Builds the full HTTP response as a byte vector.
168    /// # Returns
169    /// - `ResponseData`: response data
170    pub(super) fn build(&mut self) -> ResponseData {
171        if self.reason_phrase.is_empty() {
172            self.set_reason_phrase(HttpStatus::phrase(*self.get_status_code()));
173        }
174        let mut response_string: String = String::new();
175        self.push_http_response_first_line(&mut response_string);
176        let mut compress_type_opt: OptionCompress = None;
177        let mut connection_opt: OptionString = None;
178        let mut content_type_opt: OptionString = None;
179        let headers: ResponseHeaders = self
180            .get_mut_headers()
181            .drain()
182            .map(|(key, value)| (key.to_lowercase(), value))
183            .collect();
184        let mut unset_content_length: bool = false;
185        for (key, value) in headers.iter() {
186            if key == CONTENT_LENGTH {
187                continue;
188            } else if key == CONTENT_ENCODING {
189                compress_type_opt = Some(value.parse::<Compress>().unwrap_or_default());
190            } else if key == CONNECTION {
191                connection_opt = Some(value.to_owned());
192            } else if key == CONTENT_TYPE {
193                content_type_opt = Some(value.to_owned());
194                if value.to_ascii_lowercase() == TEXT_EVENT_STREAM {
195                    unset_content_length = true;
196                }
197            }
198            Self::push_header(&mut response_string, key, value);
199        }
200        if connection_opt.is_none() {
201            Self::push_header(&mut response_string, CONNECTION, CONNECTION_KEEP_ALIVE);
202        }
203        if content_type_opt.is_none() {
204            Self::push_header(
205                &mut response_string,
206                CONTENT_TYPE,
207                &format!("{}{}{}", TEXT_HTML, SEMICOLON_SPACE, CHARSET_UTF_8),
208            );
209        }
210        let mut body: Cow<Vec<u8>> = Cow::Borrowed(self.get_body());
211        if !unset_content_length {
212            if let Some(compress_type) = compress_type_opt {
213                if !compress_type.is_unknown() {
214                    let tmp_body: Cow<'_, Vec<u8>> =
215                        compress_type.encode(&body, DEFAULT_BUFFER_SIZE);
216                    body = Cow::Owned(tmp_body.into_owned());
217                }
218            }
219            let len_string: String = body.len().to_string();
220            Self::push_header(&mut response_string, CONTENT_LENGTH, &len_string);
221        }
222        response_string.push_str(HTTP_BR);
223        let mut response_bytes: Vec<u8> = response_string.into_bytes();
224        response_bytes.extend_from_slice(&body);
225        response_bytes
226    }
227
228    /// Sends the HTTP or HTTP websocket response body over a TCP stream.
229    ///
230    /// # Parameters
231    /// - `stream`: A mutable reference to the `TcpStream` to send the response.
232    /// - `is_websocket`: Is websocket
233    ///
234    /// # Returns
235    /// - `Ok`: If the response body is successfully sent.
236    /// - `Err`: If an error occurs during sending.
237    pub async fn send_body_with_websocket_flag(
238        &mut self,
239        stream_lock: &ArcRwLockStream,
240        is_websocket: bool,
241    ) -> ResponseResult {
242        stream_lock
243            .send_body_with_websocket_flag(self.get_body(), is_websocket)
244            .await
245    }
246
247    /// Sends the HTTP response body over a TCP stream.
248    ///
249    /// # Parameters
250    /// - `stream`: A mutable reference to the `TcpStream` to send the response.
251    ///
252    /// # Returns
253    /// - `Ok`: If the response body is successfully sent.
254    /// - `Err`: If an error occurs during sending.
255    pub async fn send_body(&mut self, stream_lock: &ArcRwLockStream) -> ResponseResult {
256        stream_lock.send_body(self.get_body()).await
257    }
258
259    /// Sends the HTTP websocket response body over a TCP stream.
260    ///
261    /// # Parameters
262    /// - `stream`: A mutable reference to the `TcpStream` to send the response.
263    ///
264    /// # Returns
265    /// - `Ok`: If the response body is successfully sent.
266    /// - `Err`: If an error occurs during sending.
267    pub async fn send_websocket_body(&mut self, stream_lock: &ArcRwLockStream) -> ResponseResult {
268        stream_lock.send_websocket_body(self.get_body()).await
269    }
270
271    /// Sends the HTTP response over a TCP stream.
272    ///
273    /// # Parameters
274    /// - `stream`: A mutable reference to the `TcpStream` to send the response.
275    ///
276    /// # Returns
277    /// - `Ok`: If the response is successfully sent.
278    /// - `Err`: If an error occurs during sending.
279    pub async fn send(&mut self, stream_lock: &ArcRwLockStream) -> ResponseResult {
280        stream_lock.send(&self.build()).await
281    }
282
283    /// Flush the TCP stream.
284    ///
285    /// - `stream_lock`: A reference to an `ArcRwLockStream` that manages the TCP stream.
286    ///
287    /// - Returns: A `ResponseResult` indicating success or failure.
288    pub async fn flush(&mut self, stream_lock: &ArcRwLockStream) -> ResponseResult {
289        stream_lock.flush().await
290    }
291
292    /// Closes the stream after sending the response.
293    ///
294    /// This function is responsible for:
295    /// - Building the response using the `build()` method.
296    /// - Setting the response using the `set_response()` method.
297    /// - Shutting down the write half of the TCP stream to indicate no more data will be sent.
298    ///
299    /// # Parameters
300    /// - `stream`: A reference to the `TcpStream` that will be closed after sending the response.
301    ///
302    /// # Returns
303    /// - `ResponseResult`: The result of the operation, indicating whether the closure was successful or if an error occurred.
304    pub async fn close(&mut self, stream_lock: &ArcRwLockStream) -> ResponseResult {
305        stream_lock.close().await
306    }
307
308    /// Converts the response to a formatted string representation.
309    ///
310    /// - Returns: A `String` containing formatted response details.
311    pub fn get_string(&self) -> String {
312        let body: &Vec<u8> = self.get_body();
313        format!(
314            "[Response] => [Version]: {}; [Status Code]: {}; [Reason]: {}; [Headers]: {:?}; [Body]: {};",
315            self.get_version(),
316            self.get_status_code(),
317            self.get_reason_phrase(),
318            self.get_headers(),
319            match std::str::from_utf8(body) {
320                Ok(string_data) => Cow::Borrowed(string_data),
321                Err(_) => Cow::Owned(format!("binary data len: {}", body.len())),
322            },
323        )
324    }
325}