http_request/response/response_binary/
impl.rsuse super::r#type::HttpResponseBinary;
use crate::{
response::{r#trait::ResponseTrait, response_text::r#type::HttpResponseText},
utils::vec::{split_multi_byte, split_whitespace},
};
use http_compress::Compress;
use http_type::*;
use std::{
collections::HashMap,
sync::{Arc, RwLock},
vec::IntoIter,
};
impl ResponseTrait for HttpResponseBinary {
type OutputText = HttpResponseText;
type OutputBinary = HttpResponseBinary;
#[inline]
fn from(response: &[u8]) -> Self
where
Self: Sized,
{
let split_lines: Vec<&[u8]> = split_multi_byte(response, HTTP_BR_BYTES);
let mut lines: IntoIter<&[u8]> = split_lines.into_iter();
let status_line: &[u8] = lines.next().unwrap_or(&[]);
let status_parts: Vec<&[u8]> = split_whitespace(&status_line);
let http_version: HttpVersion = String::from_utf8_lossy(
status_parts
.get(0)
.unwrap_or(&HttpVersion::Unknown(String::new()).to_string().as_bytes()),
)
.to_string()
.parse::<HttpVersion>()
.unwrap_or_default();
let status_code: StatusCodeUsize = status_parts
.get(1)
.and_then(|part| std::str::from_utf8(part).ok())
.unwrap_or(&StatusCode::Ok.to_string())
.parse()
.unwrap_or(StatusCode::Unknown.code());
let status_text: String = status_parts.get(2..).map_or_else(
|| StatusCode::Unknown.to_string(),
|parts| String::from_utf8_lossy(&parts.concat()).to_string(),
);
let mut headers: HashMap<String, String> = HashMap::new();
while let Some(line) = lines.next() {
if line.is_empty() {
break;
}
let header_parts: Vec<&[u8]> = split_multi_byte(&line, COLON_SPACE_BYTES);
if header_parts.len() == 2 {
let key: String = String::from_utf8_lossy(header_parts[0]).trim().to_string();
let value: String = String::from_utf8_lossy(header_parts[1]).trim().to_string();
headers.insert(key, value);
}
}
let body: Vec<u8> = lines.clone().collect::<Vec<&[u8]>>().join(BR_BYTES);
HttpResponseBinary {
http_version: Arc::new(RwLock::new(http_version)),
status_code,
status_text: Arc::new(RwLock::new(status_text)),
headers: Arc::new(RwLock::new(headers)),
body: Arc::new(RwLock::new(body)),
}
}
#[inline]
fn binary(&self) -> Self::OutputBinary {
self.clone()
}
#[inline]
fn text(&self) -> HttpResponseText {
let http_response: HttpResponseBinary = self.clone();
let body_bin: Vec<u8> = http_response
.body
.read()
.map_or(Vec::new(), |body| body.clone());
let body: String = String::from_utf8_lossy(&body_bin).to_string();
HttpResponseText {
http_version: http_response.http_version,
status_code: http_response.status_code,
status_text: http_response.status_text,
headers: http_response.headers,
body: Arc::new(RwLock::new(body)),
}
}
#[inline]
fn decode(&self, buffer_size: usize) -> HttpResponseBinary {
let http_response: HttpResponseBinary = self.clone();
let body: Vec<u8> = Compress::from(
&self
.headers
.read()
.map_or(HashMap::new(), |headers| headers.clone()),
)
.decode(
&self.body.read().map_or(Vec::new(), |body| body.clone()),
buffer_size,
);
HttpResponseBinary {
http_version: http_response.http_version,
status_code: http_response.status_code,
status_text: http_response.status_text,
headers: http_response.headers,
body: Arc::new(RwLock::new(body)),
}
}
}
impl HttpResponseBinary {
#[inline]
pub fn get_http_version(&self) -> HttpVersion {
if let Ok(http_version) = self.http_version.read() {
return http_version
.to_string()
.parse::<HttpVersion>()
.unwrap_or_default();
}
return HttpVersion::default();
}
#[inline]
pub fn get_status_code(&self) -> StatusCodeUsize {
self.status_code
}
#[inline]
pub fn get_status_text(&self) -> String {
if let Ok(status_text) = self.status_text.read() {
return status_text.to_string();
}
return StatusCode::default().to_string();
}
#[inline]
pub fn get_headers(&self) -> HttpHeaderMap {
if let Ok(headers) = self.headers.read() {
return headers.clone();
}
return HttpHeaderMap::new();
}
#[inline]
pub fn get_body(&self) -> HttpBodyVec {
if let Ok(body) = self.body.read() {
return body.clone();
}
return HttpBodyVec::new();
}
}
impl Default for HttpResponseBinary {
#[inline]
fn default() -> Self {
Self {
http_version: Arc::new(RwLock::new(HttpVersion::Unknown(String::new()))),
status_code: StatusCode::Unknown.code(),
status_text: Arc::new(RwLock::new(StatusCode::Unknown.to_string())),
headers: Arc::new(RwLock::new(HashMap::new())),
body: Arc::new(RwLock::new(Vec::new())),
}
}
}