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, 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                        headers.insert(key_str.trim().to_string(), value_str.trim().to_string());
78                    }
79                }
80            }
81        }
82        let body: Vec<u8> = match lines.len() {
83            0 => Vec::new(),
84            1 => {
85                let line: &[u8] = lines.next().unwrap_or(&[]);
86                let mut body = Vec::with_capacity(line.len());
87                body.extend_from_slice(line);
88                body
89            }
90            _ => {
91                let lines_slice: &[&[u8]] = lines.as_slice();
92                let total_size: usize = lines_slice
93                    .iter()
94                    .map(|line: &&[u8]| line.len())
95                    .sum::<usize>()
96                    + lines_slice.len().saturating_sub(1) * BR_BYTES.len();
97                let mut body: Vec<u8> = Vec::with_capacity(total_size);
98                let mut first: bool = true;
99                for line in lines {
100                    if !first {
101                        body.extend_from_slice(BR_BYTES);
102                    }
103                    body.extend_from_slice(line);
104                    first = false;
105                }
106                body
107            }
108        };
109        HttpResponseBinary {
110            http_version: Arc::new(RwLock::new(http_version)),
111            status_code,
112            status_text: Arc::new(RwLock::new(status_text)),
113            headers: Arc::new(RwLock::new(headers)),
114            body: Arc::new(RwLock::new(body)),
115        }
116    }
117
118    fn binary(&self) -> Self::OutputBinary {
119        self.clone()
120    }
121
122    fn text(&self) -> HttpResponseText {
123        let body: String = self.body.read().map_or(String::new(), |body_ref| {
124            String::from_utf8_lossy(&body_ref).into_owned()
125        });
126        HttpResponseText {
127            http_version: Arc::clone(&self.http_version),
128            status_code: self.status_code,
129            status_text: Arc::clone(&self.status_text),
130            headers: Arc::clone(&self.headers),
131            body: Arc::new(RwLock::new(body)),
132        }
133    }
134
135    fn decode(&self, buffer_size: usize) -> HttpResponseBinary {
136        let decoded_body: Vec<u8> = {
137            let headers_guard = self.headers.read();
138            let body_guard = self.body.read();
139            match (headers_guard, body_guard) {
140                (Ok(headers_ref), Ok(body_ref)) => Compress::from(&*headers_ref)
141                    .decode(&*body_ref, buffer_size)
142                    .into_owned(),
143                _ => Vec::new(),
144            }
145        };
146        HttpResponseBinary {
147            http_version: Arc::clone(&self.http_version),
148            status_code: self.status_code,
149            status_text: Arc::clone(&self.status_text),
150            headers: Arc::clone(&self.headers),
151            body: Arc::new(RwLock::new(decoded_body)),
152        }
153    }
154}
155
156impl HttpResponseBinary {
157    /// Retrieves the HTTP version associated with this response.
158    ///
159    /// # Returns
160    /// - `HttpVersion`: The HTTP version (e.g., HTTP/1.1, HTTP/2, etc.) used for the response.
161    pub fn get_http_version(&self) -> HttpVersion {
162        if let Ok(http_version) = self.http_version.read() {
163            return http_version
164                .to_string()
165                .parse::<HttpVersion>()
166                .unwrap_or_default();
167        }
168        return HttpVersion::default();
169    }
170
171    /// Retrieves the HTTP status code associated with this response.
172    ///
173    /// # Returns
174    /// - `ResponseStatusCode`: The HTTP status code as a usize (e.g., 200 for OK, 404 for Not Found).
175    pub fn get_status_code(&self) -> ResponseStatusCode {
176        self.status_code
177    }
178
179    /// Retrieves the status text associated with the HTTP status code.
180    ///
181    /// # Returns
182    /// - `String`: The human-readable status text (e.g., "OK" for status code 200, "Not Found" for status code 404).
183    pub fn get_status_text(&self) -> String {
184        if let Ok(status_text) = self.status_text.read() {
185            return status_text.to_string();
186        }
187        return HttpStatus::default().to_string();
188    }
189
190    /// Retrieves the headers of the HTTP response.
191    ///
192    /// # Returns
193    /// - `ResponseHeaders`: A map of header names and their corresponding values as key-value pairs.
194    pub fn get_headers(&self) -> ResponseHeaders {
195        if let Ok(headers) = self.headers.read() {
196            return headers.clone();
197        }
198        return hash_map_xx_hash3_64();
199    }
200
201    /// Retrieves the body content of the HTTP response.
202    ///
203    /// # Returns
204    /// - `RequestBody`: The body of the response in binary form (could be raw bytes, a stream, etc.).
205    pub fn get_body(&self) -> RequestBody {
206        if let Ok(body) = self.body.read() {
207            return body.clone();
208        }
209        return RequestBody::new();
210    }
211}
212
213impl Default for HttpResponseBinary {
214    fn default() -> Self {
215        Self {
216            http_version: Arc::new(RwLock::new(HttpVersion::Unknown(String::new()))),
217            status_code: HttpStatus::Unknown.code(),
218            status_text: Arc::new(RwLock::new(HttpStatus::Unknown.to_string())),
219            headers: Arc::new(RwLock::new(hash_map_xx_hash3_64())),
220            body: Arc::new(RwLock::new(Vec::new())),
221        }
222    }
223}