http_type/response/
impl.rs

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