http_type/response/
impl.rs

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