http_request/response/response_binary/
impl.rs

1use super::r#type::HttpResponseBinary;
2use crate::{
3    response::{r#trait::ResponseTrait, response_text::r#type::HttpResponseText},
4    utils::vec::{split_multi_byte, split_whitespace},
5};
6use http_compress::Compress;
7use http_type::*;
8use std::{
9    collections::HashMap,
10    sync::{Arc, RwLock},
11    vec::IntoIter,
12};
13
14/// Implements the `ResponseTrait` trait for `HttpResponseBinary`.
15///
16/// This implementation specifies the associated types for binary and text representations
17/// of HTTP responses, enabling seamless conversion and handling of HTTP response data.
18///
19/// # Associated Types
20/// - `OutputText`: Specifies the text representation of an HTTP response (`HttpResponseText`).
21/// - `OutputBinary`: Specifies the binary representation of an HTTP response (`HttpResponseBinary`).
22impl ResponseTrait for HttpResponseBinary {
23    type OutputText = HttpResponseText;
24    type OutputBinary = HttpResponseBinary;
25
26    #[inline]
27    fn from(response: &[u8]) -> Self
28    where
29        Self: Sized,
30    {
31        let split_lines: Vec<&[u8]> = split_multi_byte(response, HTTP_BR_BYTES);
32        let mut lines: IntoIter<&[u8]> = split_lines.into_iter();
33        let status_line: &[u8] = lines.next().unwrap_or(&[]);
34        let status_parts: Vec<&[u8]> = split_whitespace(&status_line);
35        let http_version: HttpVersion = String::from_utf8_lossy(
36            status_parts
37                .get(0)
38                .unwrap_or(&HttpVersion::Unknown(String::new()).to_string().as_bytes()),
39        )
40        .to_string()
41        .parse::<HttpVersion>()
42        .unwrap_or_default();
43        let status_code: StatusCodeUsize = status_parts
44            .get(1)
45            .and_then(|part| std::str::from_utf8(part).ok())
46            .unwrap_or(&StatusCode::Ok.to_string())
47            .parse()
48            .unwrap_or(StatusCode::Unknown.code());
49        let status_text: String = status_parts.get(2..).map_or_else(
50            || StatusCode::Unknown.to_string(),
51            |parts| String::from_utf8_lossy(&parts.concat()).to_string(),
52        );
53        let mut headers: HashMap<String, String> = HashMap::new();
54        while let Some(line) = lines.next() {
55            if line.is_empty() {
56                break;
57            }
58            let header_parts: Vec<&[u8]> = split_multi_byte(&line, COLON_SPACE_BYTES);
59            if header_parts.len() == 2 {
60                let key: String = String::from_utf8_lossy(header_parts[0]).trim().to_string();
61                let value: String = String::from_utf8_lossy(header_parts[1]).trim().to_string();
62                headers.insert(key, value);
63            }
64        }
65        let body: Vec<u8> = lines.clone().collect::<Vec<&[u8]>>().join(BR_BYTES);
66        HttpResponseBinary {
67            http_version: Arc::new(RwLock::new(http_version)),
68            status_code,
69            status_text: Arc::new(RwLock::new(status_text)),
70            headers: Arc::new(RwLock::new(headers)),
71            body: Arc::new(RwLock::new(body)),
72        }
73    }
74
75    #[inline]
76    fn binary(&self) -> Self::OutputBinary {
77        self.clone()
78    }
79
80    #[inline]
81    fn text(&self) -> HttpResponseText {
82        let http_response: HttpResponseBinary = self.clone();
83        let body_bin: Vec<u8> = http_response
84            .body
85            .read()
86            .map_or(Vec::new(), |body| body.clone());
87        let body: String = String::from_utf8_lossy(&body_bin).to_string();
88        HttpResponseText {
89            http_version: http_response.http_version,
90            status_code: http_response.status_code,
91            status_text: http_response.status_text,
92            headers: http_response.headers,
93            body: Arc::new(RwLock::new(body)),
94        }
95    }
96
97    #[inline]
98    fn decode(&self, buffer_size: usize) -> HttpResponseBinary {
99        let http_response: HttpResponseBinary = self.clone();
100        let body: Vec<u8> = Compress::from(
101            &self
102                .headers
103                .read()
104                .map_or(HashMap::new(), |headers| headers.clone()),
105        )
106        .decode(
107            &self.body.read().map_or(Vec::new(), |body| body.clone()),
108            buffer_size,
109        )
110        .into_owned();
111        HttpResponseBinary {
112            http_version: http_response.http_version,
113            status_code: http_response.status_code,
114            status_text: http_response.status_text,
115            headers: http_response.headers,
116            body: Arc::new(RwLock::new(body)),
117        }
118    }
119}
120
121impl HttpResponseBinary {
122    /// Retrieves the HTTP version associated with this response.
123    ///
124    /// # Returns
125    /// - `HttpVersion`: The HTTP version (e.g., HTTP/1.1, HTTP/2, etc.) used for the response.
126    #[inline]
127    pub fn get_http_version(&self) -> HttpVersion {
128        if let Ok(http_version) = self.http_version.read() {
129            return http_version
130                .to_string()
131                .parse::<HttpVersion>()
132                .unwrap_or_default();
133        }
134        return HttpVersion::default();
135    }
136
137    /// Retrieves the HTTP status code associated with this response.
138    ///
139    /// # Returns
140    /// - `StatusCodeUsize`: The HTTP status code as a usize (e.g., 200 for OK, 404 for Not Found).
141    #[inline]
142    pub fn get_status_code(&self) -> StatusCodeUsize {
143        self.status_code
144    }
145
146    /// Retrieves the status text associated with the HTTP status code.
147    ///
148    /// # Returns
149    /// - `String`: The human-readable status text (e.g., "OK" for status code 200, "Not Found" for status code 404).
150    #[inline]
151    pub fn get_status_text(&self) -> String {
152        if let Ok(status_text) = self.status_text.read() {
153            return status_text.to_string();
154        }
155        return StatusCode::default().to_string();
156    }
157
158    /// Retrieves the headers of the HTTP response.
159    ///
160    /// # Returns
161    /// - `HttpHeaderMap`: A map of header names and their corresponding values as key-value pairs.
162    #[inline]
163    pub fn get_headers(&self) -> HttpHeaderMap {
164        if let Ok(headers) = self.headers.read() {
165            return headers.clone();
166        }
167        return HttpHeaderMap::new();
168    }
169
170    /// Retrieves the body content of the HTTP response.
171    ///
172    /// # Returns
173    /// - `HttpBodyVec`: The body of the response in binary form (could be raw bytes, a stream, etc.).
174    #[inline]
175    pub fn get_body(&self) -> HttpBodyVec {
176        if let Ok(body) = self.body.read() {
177            return body.clone();
178        }
179        return HttpBodyVec::new();
180    }
181}
182
183impl Default for HttpResponseBinary {
184    #[inline]
185    fn default() -> Self {
186        Self {
187            http_version: Arc::new(RwLock::new(HttpVersion::Unknown(String::new()))),
188            status_code: StatusCode::Unknown.code(),
189            status_text: Arc::new(RwLock::new(StatusCode::Unknown.to_string())),
190            headers: Arc::new(RwLock::new(HashMap::new())),
191            body: Arc::new(RwLock::new(Vec::new())),
192        }
193    }
194}