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: HttpVersion::HTTP1_1,
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 first value of a response header by its key.
42 ///
43 /// # Parameters
44 /// - `key`: The header's key, which can be of any type that implements `Into<ResponseHeadersKey>`.
45 ///
46 /// # Returns
47 /// - `OptionResponseHeadersValueItem`: Returns `Some(value)` if the key exists and has at least one value,
48 /// or `None` if the key does not exist or has no values.
49 pub fn get_header_front<K>(&self, key: K) -> OptionResponseHeadersValueItem
50 where
51 K: Into<ResponseHeadersKey>,
52 {
53 self.headers
54 .get(&key.into())
55 .and_then(|values| values.front().cloned())
56 }
57
58 /// Retrieves the last value of a response header by its key.
59 ///
60 /// # Parameters
61 /// - `key`: The header's key, which can be of any type that implements `Into<ResponseHeadersKey>`.
62 ///
63 /// # Returns
64 /// - `OptionResponseHeadersValueItem`: Returns `Some(value)` if the key exists and has at least one value,
65 /// or `None` if the key does not exist or has no values.
66 pub fn get_header_back<K>(&self, key: K) -> OptionResponseHeadersValueItem
67 where
68 K: Into<ResponseHeadersKey>,
69 {
70 self.headers
71 .get(&key.into())
72 .and_then(|values| values.back().cloned())
73 }
74
75 /// Checks if a header exists in the response.
76 ///
77 /// # Parameters
78 /// - `key`: The header key to check, which will be converted into a `ResponseHeadersKey`.
79 ///
80 /// # Returns
81 /// - `true`: If the header exists.
82 /// - `false`: If the header does not exist.
83 pub fn has_header<K>(&self, key: K) -> bool
84 where
85 K: Into<ResponseHeadersKey>,
86 {
87 let key: ResponseHeadersKey = key.into().to_lowercase();
88 self.headers.contains_key(&key)
89 }
90
91 /// Checks if a header contains a specific value.
92 ///
93 /// # Parameters
94 /// - `key`: The header key to check, which will be converted into a `ResponseHeadersKey`.
95 /// - `value`: The value to search for in the header.
96 ///
97 /// # Returns
98 /// - `true`: If the header exists and contains the specified value.
99 /// - `false`: If the header does not exist or does not contain the value.
100 pub fn has_header_value<K, V>(&self, key: K, value: V) -> bool
101 where
102 K: Into<ResponseHeadersKey>,
103 V: Into<ResponseHeadersValueItem>,
104 {
105 let key: ResponseHeadersKey = key.into();
106 let value: ResponseHeadersValueItem = value.into();
107 if let Some(values) = self.headers.get(&key) {
108 values.contains(&value)
109 } else {
110 false
111 }
112 }
113
114 /// Gets the number of headers in the response.
115 ///
116 /// # Returns
117 /// - The number of unique header keys in the response.
118 pub fn get_headers_len(&self) -> usize {
119 self.headers.len()
120 }
121
122 /// Gets the number of values for a specific header key.
123 ///
124 /// # Parameters
125 /// - `key`: The header key to count values for, which will be converted into a `ResponseHeadersKey`.
126 ///
127 /// # Returns
128 /// - The number of values for the specified header key. Returns 0 if the header does not exist.
129 pub fn get_header_len<K>(&self, key: K) -> usize
130 where
131 K: Into<ResponseHeadersKey>,
132 {
133 let key: ResponseHeadersKey = key.into().to_lowercase();
134 self.headers.get(&key).map_or(0, |values| values.len())
135 }
136
137 /// Gets the total number of header values in the response.
138 ///
139 /// This counts all values across all headers, so a header with multiple values
140 /// will contribute more than one to the total count.
141 ///
142 /// # Returns
143 /// - The total number of header values in the response.
144 pub fn get_headers_values_len(&self) -> usize {
145 self.headers.values().map(|values| values.len()).sum()
146 }
147
148 /// Retrieves the body content of the object as a UTF-8 encoded string.
149 ///
150 /// This method uses `String::from_utf8_lossy` to convert the byte slice returned by `self.get_body()` into a string.
151 /// If the byte slice contains invalid UTF-8 sequences, they will be replaced with the Unicode replacement character (�).
152 ///
153 /// # Returns
154 /// A `String` containing the body content.
155 pub fn get_body_string(&self) -> String {
156 String::from_utf8_lossy(self.get_body()).into_owned()
157 }
158
159 /// Deserializes the body content of the object into a specified type `T`.
160 ///
161 /// This method first retrieves the body content as a UTF-8 encoded string using `self.get_body()`.
162 /// It then attempts to deserialize the string into the specified type `T` using `json_from_slice`.
163 ///
164 /// # Type Parameters
165 /// - `T`: The target type to deserialize into. It must implement the `DeserializeOwned` trait.
166 ///
167 /// # Returns
168 /// - `Ok(T)`: The deserialized object of type `T` if the deserialization is successful.
169 /// - `Err(ResultJsonError)`: An error if the deserialization fails (e.g., invalid JSON format or type mismatch).
170 pub fn get_body_json<T>(&self) -> ResultJsonError<T>
171 where
172 T: DeserializeOwned,
173 {
174 json_from_slice(self.get_body())
175 }
176
177 /// Adds a header to the response.
178 ///
179 /// This function appends a value to the response headers.
180 /// If the header already exists, the new value will be added to the existing values.
181 ///
182 /// # Parameters
183 /// - `key`: The header key, which will be converted into a `ResponseHeadersKey`.
184 /// - `value`: The value of the header, which will be converted into a String.
185 pub fn set_header<K, V>(&mut self, key: K, value: V) -> &mut Self
186 where
187 K: Into<ResponseHeadersKey>,
188 V: Into<String>,
189 {
190 let key: ResponseHeadersKey = key.into().to_lowercase();
191 if key.trim().is_empty() || key == CONTENT_LENGTH {
192 return self;
193 }
194 let value: String = value.into();
195 self.headers
196 .entry(key)
197 .or_insert_with(VecDeque::new)
198 .push_back(value);
199 self
200 }
201
202 /// Replaces all values for a header in the response.
203 ///
204 /// This function replaces all existing values for a header with a single new value.
205 ///
206 /// # Parameters
207 /// - `key`: The header key, which will be converted into a `ResponseHeadersKey`.
208 /// - `value`: The value of the header, which will be converted into a String.
209 pub fn replace_header<K, V>(&mut self, key: K, value: V) -> &mut Self
210 where
211 K: Into<ResponseHeadersKey>,
212 V: Into<String>,
213 {
214 let key: ResponseHeadersKey = key.into().to_lowercase();
215 if key.trim().is_empty() {
216 return self;
217 }
218 let value: String = value.into();
219 let mut deque: VecDeque<String> = VecDeque::new();
220 deque.push_back(value);
221 self.headers.insert(key, deque);
222 self
223 }
224
225 /// Removes a header from the response.
226 ///
227 /// This function removes all values for the specified header key.
228 ///
229 /// # Parameters
230 /// - `key`: The header key to remove, which will be converted into a `ResponseHeadersKey`.
231 pub fn remove_header<K>(&mut self, key: K) -> &mut Self
232 where
233 K: Into<ResponseHeadersKey>,
234 {
235 let key: ResponseHeadersKey = key.into().to_lowercase();
236 let _ = self.headers.remove(&key).is_some();
237 self
238 }
239
240 /// Removes a specific value from a header in the response.
241 ///
242 /// This function removes only the specified value from the header.
243 /// If the header has multiple values, only the matching value is removed.
244 /// If this was the last value for the header, the entire header is removed.
245 ///
246 /// # Parameters
247 /// - `key`: The header key, which will be converted into a `ResponseHeadersKey`.
248 /// - `value`: The specific value to remove from the header.
249 pub fn remove_header_value<K, V>(&mut self, key: K, value: V) -> &mut Self
250 where
251 K: Into<ResponseHeadersKey>,
252 V: Into<String>,
253 {
254 let key: ResponseHeadersKey = key.into().to_lowercase();
255 let value: String = value.into();
256 if let Some(values) = self.headers.get_mut(&key) {
257 values.retain(|v| v != &value);
258 if values.is_empty() {
259 self.headers.remove(&key);
260 }
261 }
262 self
263 }
264
265 /// Clears all headers from the response.
266 ///
267 /// This function removes all headers, leaving the headers map empty.
268 pub fn clear_headers(&mut self) -> &mut Self {
269 self.headers.clear();
270 self
271 }
272
273 /// Set the body of the response.
274 ///
275 /// This method allows you to set the body of the response by converting the provided
276 /// value into a `ResponseBody` type. The `body` is updated with the converted value,
277 /// and the method returns a mutable reference to the current instance for method chaining.
278 ///
279 /// # Parameters
280 /// - `body`: The body of the response to be set. It can be any type that can be converted
281 /// into a `ResponseBody` using the `Into` trait.
282 ///
283 /// # Return Value
284 /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
285 /// Set the body of the response.
286 ///
287 /// This method allows you to set the body of the response by converting the provided
288 /// value into a `ResponseBody` type. The `body` is updated with the converted value,
289 /// and the method returns a mutable reference to the current instance for method chaining.
290 ///
291 /// # Parameters
292 /// - `body`: The body of the response to be set. It can be any type that can be converted
293 /// into a `ResponseBody` using the `Into` trait.
294 ///
295 /// # Return Value
296 /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
297 pub fn set_body<T>(&mut self, body: T) -> &mut Self
298 where
299 T: Into<ResponseBody>,
300 {
301 self.body = body.into();
302 self
303 }
304
305 /// Set the reason phrase of the response.
306 ///
307 /// This method allows you to set the reason phrase of the response by converting the
308 /// provided value into a `ResponseReasonPhrase` type. The `reason_phrase` is updated
309 /// with the converted value, and the method returns a mutable reference to the current
310 /// instance for method chaining.
311 ///
312 /// # Parameters
313 /// - `reason_phrase`: The reason phrase to be set for the response. It can be any type
314 /// that can be converted into a `ResponseReasonPhrase` using the `Into` trait.
315 ///
316 /// # Return Value
317 /// - Returns a mutable reference to the current instance of the struct, enabling method chaining.
318 pub fn set_reason_phrase<T>(&mut self, reason_phrase: T) -> &mut Self
319 where
320 T: Into<ResponseReasonPhrase>,
321 {
322 self.reason_phrase = reason_phrase.into();
323 self
324 }
325
326 /// Pushes a header with a key and value into the response string.
327 ///
328 /// # Parameters
329 /// - `response_string`: A mutable reference to the string where the header will be added.
330 /// - `key`: The header key as a string slice (`&str`).
331 /// - `value`: The header value as a string slice (`&str`).
332 fn push_header(response_string: &mut String, key: &str, value: &str) {
333 response_string.push_str(key);
334 response_string.push_str(COLON_SPACE);
335 response_string.push_str(value);
336 response_string.push_str(HTTP_BR);
337 }
338
339 /// Pushes the first line of an HTTP response (version, status code, and reason phrase) into the response string.
340 /// This corresponds to the status line of the HTTP response.
341 ///
342 /// # Parameters
343 /// - `response_string`: A mutable reference to the string where the first line will be added.
344 fn push_http_first_line(&self, response_string: &mut String) {
345 response_string.push_str(&self.get_version().to_string());
346 response_string.push_str(SPACE);
347 response_string.push_str(&self.get_status_code().to_string());
348 response_string.push_str(SPACE);
349 response_string.push_str(self.get_reason_phrase());
350 response_string.push_str(HTTP_BR);
351 }
352
353 /// Builds the full HTTP response as a byte vector.
354 /// # Returns
355 /// - `ResponseData`: response data
356 pub fn build(&mut self) -> ResponseData {
357 if self.reason_phrase.is_empty() {
358 self.set_reason_phrase(HttpStatus::phrase(*self.get_status_code()));
359 }
360 let mut response_string: String = String::new();
361 self.push_http_first_line(&mut response_string);
362 let mut compress_type_opt: OptionCompress = None;
363 let mut connection_opt: OptionString = None;
364 let mut content_type_opt: OptionString = None;
365 let headers: ResponseHeaders = self
366 .get_mut_headers()
367 .drain()
368 .map(|(key, value)| (key.to_lowercase(), value))
369 .collect();
370 let mut unset_content_length: bool = false;
371 for (key, values) in headers.iter() {
372 for value in values.iter() {
373 if key == CONTENT_ENCODING {
374 compress_type_opt = Some(value.parse::<Compress>().unwrap_or_default());
375 } else if key == CONNECTION {
376 connection_opt = Some(value.to_owned());
377 } else if key == CONTENT_TYPE {
378 content_type_opt = Some(value.to_owned());
379 if value.eq_ignore_ascii_case(TEXT_EVENT_STREAM) {
380 unset_content_length = true;
381 }
382 }
383 Self::push_header(&mut response_string, key, value);
384 }
385 }
386 if connection_opt.is_none() {
387 Self::push_header(&mut response_string, CONNECTION, KEEP_ALIVE);
388 }
389 if content_type_opt.is_none() {
390 let mut content_type: String = String::with_capacity(
391 TEXT_HTML.len() + SEMICOLON_SPACE.len() + CHARSET_UTF_8.len(),
392 );
393 content_type.push_str(TEXT_HTML);
394 content_type.push_str(SEMICOLON_SPACE);
395 content_type.push_str(CHARSET_UTF_8);
396 Self::push_header(&mut response_string, CONTENT_TYPE, &content_type);
397 }
398 let mut body: Cow<Vec<u8>> = Cow::Borrowed(self.get_body());
399 if !unset_content_length {
400 if let Some(compress_type) = compress_type_opt {
401 if !compress_type.is_unknown() {
402 let tmp_body: Cow<'_, Vec<u8>> =
403 compress_type.encode(&body, DEFAULT_BUFFER_SIZE);
404 body = Cow::Owned(tmp_body.into_owned());
405 }
406 }
407 let len_string: String = body.len().to_string();
408 Self::push_header(&mut response_string, CONTENT_LENGTH, &len_string);
409 }
410 response_string.push_str(HTTP_BR);
411 let mut response_bytes: Vec<u8> = response_string.into_bytes();
412 response_bytes.extend_from_slice(&body);
413 response_bytes
414 }
415
416 /// Converts the response to a formatted string representation.
417 ///
418 /// - Returns: A `String` containing formatted response details.
419 pub fn get_string(&self) -> String {
420 let body: &Vec<u8> = self.get_body();
421 let body_type: &'static str = if std::str::from_utf8(body).is_ok() {
422 PLAIN
423 } else {
424 BINARY
425 };
426 format!(
427 "[Response] => [version]: {}; [status code]: {}; [reason]: {}; [headers]: {:?}; [body]: {} bytes {};",
428 self.get_version(),
429 self.get_status_code(),
430 self.get_reason_phrase(),
431 self.get_headers(),
432 body.len(),
433 body_type
434 )
435 }
436}