http_request/response/response_binary/
impl.rs

1use crate::*;
2
3/// Implements the `ResponseTrait` trait for `HttpResponseBinary`.
4///
5/// This implementation specifies the associated types for binary and text representations
6/// of HTTP responses, enabling seamless conversion and handling of HTTP response data.
7///
8/// # Associated Types
9/// - `OutputText`: Specifies the text representation of an HTTP response (`HttpResponseText`).
10/// - `OutputBinary`: Specifies the binary representation of an HTTP response (`HttpResponseBinary`).
11impl ResponseTrait for HttpResponseBinary {
12    type OutputText = HttpResponseText;
13    type OutputBinary = HttpResponseBinary;
14    fn from(response: &[u8]) -> Self
15    where
16        Self: Sized,
17    {
18        let split_lines: Vec<&[u8]> = split_multi_byte(response, HTTP_BR_BYTES);
19        let mut lines: IntoIter<&[u8]> = split_lines.into_iter();
20        let status_line: &[u8] = lines.next().unwrap_or(&[]);
21        let status_parts: Vec<&[u8]> = split_whitespace(&status_line);
22        let http_version: HttpVersion = status_parts
23            .get(0)
24            .and_then(|part: &&[u8]| from_utf8(part).ok())
25            .and_then(|version_str: &str| version_str.parse::<HttpVersion>().ok())
26            .unwrap_or_default();
27        let status_code: ResponseStatusCode = status_parts
28            .get(1)
29            .and_then(|part: &&[u8]| from_utf8(part).ok())
30            .and_then(|code_str: &str| code_str.parse().ok())
31            .unwrap_or(HttpStatus::Unknown.code());
32        let status_text: String = status_parts.get(2..).map_or_else(
33            || HttpStatus::Unknown.to_string(),
34            |parts: &[&[u8]]| {
35                if parts.is_empty() {
36                    HttpStatus::Unknown.to_string()
37                } else if parts.len() == 1 {
38                    String::from_utf8_lossy(parts[0]).into_owned()
39                } else {
40                    let total_len: usize =
41                        parts.iter().map(|p: &&[u8]| p.len()).sum::<usize>() + parts.len() - 1;
42                    let mut result: String = String::with_capacity(total_len);
43                    for (i, part) in parts.iter().enumerate() {
44                        if i > 0 {
45                            result.push(' ');
46                        }
47                        result.push_str(&String::from_utf8_lossy(part));
48                    }
49                    result
50                }
51            },
52        );
53        let mut headers: HashMapXxHash3_64<String, VecDeque<String>> = hash_map_xx_hash3_64();
54        for line in lines.by_ref() {
55            if line.is_empty() {
56                break;
57            }
58            let mut colon_pos: Option<usize> = None;
59            for (i, &byte) in line.iter().enumerate() {
60                if byte == b':' {
61                    colon_pos = Some(i);
62                    break;
63                }
64            }
65            if let Some(pos) = colon_pos {
66                if pos > 0 && pos + 1 < line.len() {
67                    let key_bytes: &[u8] = &line[..pos];
68                    let value_start: usize = if line.get(pos + 1) == Some(&b' ') {
69                        pos + 2
70                    } else {
71                        pos + 1
72                    };
73                    let value_bytes: &[u8] = &line[value_start..];
74                    if let (Ok(key_str), Ok(value_str)) =
75                        (from_utf8(key_bytes), from_utf8(value_bytes))
76                    {
77                        let mut value_deque: VecDeque<String> = VecDeque::new();
78                        value_deque.push_front(value_str.trim().to_string());
79                        headers.insert(key_str.trim().to_string(), value_deque);
80                    }
81                }
82            }
83        }
84        let body: Vec<u8> = match lines.len() {
85            0 => Vec::new(),
86            1 => {
87                let line: &[u8] = lines.next().unwrap_or(&[]);
88                let mut body = Vec::with_capacity(line.len());
89                body.extend_from_slice(line);
90                body
91            }
92            _ => {
93                let lines_slice: &[&[u8]] = lines.as_slice();
94                let total_size: usize = lines_slice
95                    .iter()
96                    .map(|line: &&[u8]| line.len())
97                    .sum::<usize>()
98                    + lines_slice.len().saturating_sub(1) * BR_BYTES.len();
99                let mut body: Vec<u8> = Vec::with_capacity(total_size);
100                let mut first: bool = true;
101                for line in lines {
102                    if !first {
103                        body.extend_from_slice(BR_BYTES);
104                    }
105                    body.extend_from_slice(line);
106                    first = false;
107                }
108                body
109            }
110        };
111        HttpResponseBinary {
112            http_version: Arc::new(RwLock::new(http_version)),
113            status_code,
114            status_text: Arc::new(RwLock::new(status_text)),
115            headers: Arc::new(RwLock::new(headers)),
116            body: Arc::new(RwLock::new(body)),
117        }
118    }
119
120    fn binary(&self) -> Self::OutputBinary {
121        self.clone()
122    }
123
124    fn text(&self) -> HttpResponseText {
125        let body: String = self.body.read().map_or(String::new(), |body_ref| {
126            String::from_utf8_lossy(&body_ref).into_owned()
127        });
128        HttpResponseText {
129            http_version: Arc::clone(&self.http_version),
130            status_code: self.status_code,
131            status_text: Arc::clone(&self.status_text),
132            headers: Arc::clone(&self.headers),
133            body: Arc::new(RwLock::new(body)),
134        }
135    }
136
137    fn decode(&self, buffer_size: usize) -> HttpResponseBinary {
138        let decoded_body: Vec<u8> = {
139            let headers_guard = self.headers.read();
140            let body_guard = self.body.read();
141            match (headers_guard, body_guard) {
142                (Ok(headers_ref), Ok(body_ref)) => {
143                    let mut string_headers: HashMapXxHash3_64<String, String> =
144                        hash_map_xx_hash3_64();
145                    for (key, value_deque) in headers_ref.iter() {
146                        if let Some(first_value) = value_deque.front() {
147                            string_headers.insert(key.clone(), first_value.clone());
148                        }
149                    }
150                    Compress::from(&string_headers)
151                        .decode(&*body_ref, buffer_size)
152                        .into_owned()
153                }
154                _ => Vec::new(),
155            }
156        };
157        HttpResponseBinary {
158            http_version: Arc::clone(&self.http_version),
159            status_code: self.status_code,
160            status_text: Arc::clone(&self.status_text),
161            headers: Arc::clone(&self.headers),
162            body: Arc::new(RwLock::new(decoded_body)),
163        }
164    }
165}
166
167impl HttpResponseBinary {
168    /// Retrieves the HTTP version associated with this response.
169    ///
170    /// # Returns
171    /// - `HttpVersion`: The HTTP version (e.g., HTTP/1.1, HTTP/2, etc.) used for the response.
172    pub fn get_http_version(&self) -> HttpVersion {
173        if let Ok(http_version) = self.http_version.read() {
174            return http_version
175                .to_string()
176                .parse::<HttpVersion>()
177                .unwrap_or_default();
178        }
179        return HttpVersion::default();
180    }
181
182    /// Retrieves the HTTP status code associated with this response.
183    ///
184    /// # Returns
185    /// - `ResponseStatusCode`: The HTTP status code as a usize (e.g., 200 for OK, 404 for Not Found).
186    pub fn get_status_code(&self) -> ResponseStatusCode {
187        self.status_code
188    }
189
190    /// Retrieves the status text associated with the HTTP status code.
191    ///
192    /// # Returns
193    /// - `String`: The human-readable status text (e.g., "OK" for status code 200, "Not Found" for status code 404).
194    pub fn get_status_text(&self) -> String {
195        if let Ok(status_text) = self.status_text.read() {
196            return status_text.to_string();
197        }
198        return HttpStatus::default().to_string();
199    }
200
201    /// Retrieves the headers of the HTTP response.
202    ///
203    /// # Returns
204    /// - `ResponseHeaders`: A map of header names and their corresponding values as key-value pairs.
205    pub fn get_headers(&self) -> ResponseHeaders {
206        if let Ok(headers) = self.headers.read() {
207            return headers.clone();
208        }
209        return hash_map_xx_hash3_64();
210    }
211
212    /// Retrieves the body content of the HTTP response.
213    ///
214    /// # Returns
215    /// - `RequestBody`: The body of the response in binary form (could be raw bytes, a stream, etc.).
216    pub fn get_body(&self) -> RequestBody {
217        if let Ok(body) = self.body.read() {
218            return body.clone();
219        }
220        return RequestBody::new();
221    }
222}
223
224impl Default for HttpResponseBinary {
225    fn default() -> Self {
226        Self {
227            http_version: Arc::new(RwLock::new(HttpVersion::Unknown(String::new()))),
228            status_code: HttpStatus::Unknown.code(),
229            status_text: Arc::new(RwLock::new(HttpStatus::Unknown.to_string())),
230            headers: Arc::new(RwLock::new(hash_map_xx_hash3_64())),
231            body: Arc::new(RwLock::new(Vec::new())),
232        }
233    }
234}