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}