http_type/response/
impl.rs

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