use super::*;
impl Error for ResponseError {}
impl From<io::Error> for ResponseError {
#[inline(always)]
fn from(error: io::Error) -> Self {
ResponseError::Send(error.to_string())
}
}
impl Display for ResponseError {
#[inline(always)]
fn fmt(&self, data: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::NotFoundStream => {
write!(data, "Not found stream")
}
Self::ConnectionClosed => {
write!(data, "Connection has been closed")
}
Self::Terminated => {
write!(data, "Current processing has been terminated")
}
Self::Send(error) => write!(data, "Send error{COLON_SPACE}{error}"),
Self::FlushError(error) => write!(data, "Flush error{COLON_SPACE}{error}"),
Self::Unknown => write!(data, "Unknown error"),
}
}
}
impl Default for Response {
#[inline(always)]
fn default() -> Self {
let http_status: HttpStatus = HttpStatus::default();
Self {
version: HttpVersion::Http1_1,
status_code: http_status.code(),
reason_phrase: http_status.to_string(),
headers: hash_map_xx_hash3_64(),
body: Vec::new(),
}
}
}
impl Response {
#[inline(always)]
fn push_header(response_bytes: &mut Vec<u8>, key: &str, value: &str) {
response_bytes.extend_from_slice(key.as_bytes());
response_bytes.extend_from_slice(COLON.as_bytes());
response_bytes.extend_from_slice(value.as_bytes());
response_bytes.extend_from_slice(HTTP_BR.as_bytes());
}
#[inline(always)]
pub fn try_get_header<K>(&self, key: K) -> Option<ResponseHeadersValue>
where
K: AsRef<str>,
{
self.headers.get(key.as_ref()).cloned()
}
#[inline(always)]
pub fn get_header<K>(&self, key: K) -> ResponseHeadersValue
where
K: AsRef<str>,
{
self.try_get_header(key).unwrap()
}
#[inline(always)]
pub fn try_get_header_front<K>(&self, key: K) -> Option<ResponseHeadersValueItem>
where
K: AsRef<str>,
{
self.headers
.get(key.as_ref())
.and_then(|data: &VecDeque<String>| data.front().cloned())
}
#[inline(always)]
pub fn get_header_front<K>(&self, key: K) -> ResponseHeadersValueItem
where
K: AsRef<str>,
{
self.try_get_header_front(key).unwrap()
}
#[inline(always)]
pub fn try_get_header_back<K>(&self, key: K) -> Option<ResponseHeadersValueItem>
where
K: AsRef<str>,
{
self.headers
.get(key.as_ref())
.and_then(|data: &VecDeque<String>| data.back().cloned())
}
#[inline(always)]
pub fn get_header_back<K>(&self, key: K) -> ResponseHeadersValueItem
where
K: AsRef<str>,
{
self.try_get_header_back(key).unwrap()
}
#[inline(always)]
pub fn has_header<K>(&self, key: K) -> bool
where
K: AsRef<str>,
{
self.get_headers().contains_key(key.as_ref())
}
#[inline(always)]
pub fn has_header_value<K, V>(&self, key: K, value: V) -> bool
where
K: AsRef<str>,
V: AsRef<str>,
{
if let Some(values) = self.get_headers().get(key.as_ref()) {
values.contains(&value.as_ref().to_owned())
} else {
false
}
}
#[inline(always)]
pub fn get_headers_size(&self) -> usize {
self.headers.len()
}
#[inline(always)]
pub fn try_get_header_size<K>(&self, key: K) -> Option<usize>
where
K: AsRef<str>,
{
self.headers
.get(key.as_ref())
.map(|data: &VecDeque<String>| data.len())
}
#[inline(always)]
pub fn get_header_size<K>(&self, key: K) -> usize
where
K: AsRef<str>,
{
self.try_get_header_size(key).unwrap()
}
#[inline(always)]
pub fn get_headers_values_size(&self) -> usize {
self.headers
.values()
.map(|data: &VecDeque<String>| data.len())
.sum()
}
#[inline(always)]
pub fn get_body_string(&self) -> String {
String::from_utf8_lossy(self.get_body()).into_owned()
}
pub fn try_get_body_json<T>(&self) -> Result<T, serde_json::Error>
where
T: DeserializeOwned,
{
serde_json::from_slice(self.get_body())
}
pub fn get_body_json<T>(&self) -> T
where
T: DeserializeOwned,
{
self.try_get_body_json().unwrap()
}
#[inline(always)]
fn should_skip_header(&self, key: &str) -> bool {
key.trim().is_empty() || key == CONTENT_LENGTH
}
#[inline(always)]
fn set_header_without_check<K, V>(&mut self, key: K, value: V) -> &mut Self
where
K: AsRef<str>,
V: AsRef<str>,
{
let key: &str = key.as_ref();
let value: &str = value.as_ref();
if let Some(values) = self.get_mut_headers().get_mut(key) {
values.truncate(1);
if let Some(slot) = values.front_mut() {
slot.clear();
slot.push_str(value);
} else {
values.push_back(value.to_owned());
}
return self;
}
let (mut name, mut values): (String, VecDeque<String>) =
take_header_entry().unwrap_or_else(|| (String::new(), VecDeque::new()));
name.clear();
name.push_str(key);
while values.len() > 1 {
values.pop_back();
}
if values.is_empty() {
values.push_back(String::new());
}
if let Some(slot) = values.front_mut() {
slot.clear();
slot.push_str(value.as_ref());
}
self.get_mut_headers().insert(name, values);
self
}
#[inline(always)]
pub fn set_header<K, V>(&mut self, key: K, value: V) -> &mut Self
where
K: AsRef<str>,
V: AsRef<str>,
{
let key: &str = key.as_ref();
if self.should_skip_header(key) {
return self;
}
self.set_header_without_check(key, value)
}
#[inline(always)]
pub fn add_header<K, V>(&mut self, key: K, value: V) -> &mut Self
where
K: AsRef<str>,
V: AsRef<str>,
{
let key: ResponseHeadersKey = key.as_ref().to_owned();
if self.should_skip_header(&key) {
return self;
}
self.get_mut_headers()
.entry(key)
.or_default()
.push_back(value.as_ref().to_owned());
self
}
#[inline(always)]
pub fn remove_header<K>(&mut self, key: K) -> &mut Self
where
K: AsRef<str>,
{
let _: bool = self.get_mut_headers().remove(key.as_ref()).is_some();
self
}
#[inline(always)]
pub fn remove_header_value<K, V>(&mut self, key: K, value: V) -> &mut Self
where
K: AsRef<str>,
V: AsRef<str>,
{
let key: ResponseHeadersKey = key.as_ref().to_owned();
if let Some(values) = self.get_mut_headers().get_mut(&key) {
values.retain(|data: &String| data != &value.as_ref().to_owned());
if values.is_empty() {
self.get_mut_headers().remove(&key);
}
}
self
}
#[inline(always)]
pub fn clear_headers(&mut self) -> &mut Self {
self.get_mut_headers().clear();
self
}
pub fn reset(&mut self) -> &mut Self {
let http_status: HttpStatus = HttpStatus::default();
self.set_status_code(http_status.code());
let stored: &mut ResponseReasonPhrase = self.get_mut_reason_phrase();
stored.clear();
stored.push_str(HttpStatus::phrase_ref(http_status.code()));
self.recycle_headers();
self.get_mut_body().clear();
self
}
fn recycle_headers(&mut self) {
let headers: &mut ResponseHeaders = self.get_mut_headers();
if headers.is_empty() {
return;
}
for (key, values) in headers.drain() {
return_header_entry((key, values));
}
}
#[inline(always)]
pub fn try_get_cookies(&self) -> Option<Cookies> {
self.try_get_header_back(SET_COOKIE)
.map(|cookie_header: String| Cookie::parse(cookie_header))
}
#[inline(always)]
pub fn get_cookies(&self) -> Cookies {
self.try_get_cookies().unwrap()
}
#[inline(always)]
pub fn try_get_cookie<K>(&self, key: K) -> Option<CookieValue>
where
K: AsRef<str>,
{
self.try_get_cookies()
.and_then(|cookies: Cookies| cookies.get(key.as_ref()).cloned())
}
#[inline(always)]
pub fn get_cookie<K>(&self, key: K) -> CookieValue
where
K: AsRef<str>,
{
self.try_get_cookie(key).unwrap()
}
pub fn build(&mut self) -> ResponseData {
if self.get_reason_phrase().is_empty() || self.get_reason_phrase().as_str() == OK {
let phrase: &'static str = HttpStatus::phrase_ref(self.get_status_code());
let stored: &mut ResponseReasonPhrase = self.get_mut_reason_phrase();
stored.clear();
stored.push_str(phrase);
}
let compress_type_opt: Option<Compress> = self
.get_headers()
.get(CONTENT_ENCODING)
.and_then(|values: &VecDeque<String>| values.back())
.map(|data: &String| data.parse::<Compress>().unwrap_or_default());
if self
.get_headers()
.get(CONNECTION)
.and_then(|values: &VecDeque<String>| values.back())
.is_none()
{
self.set_header_without_check(CONNECTION, KEEP_ALIVE);
}
if self
.get_headers()
.get(CONTENT_TYPE)
.and_then(|values: &VecDeque<String>| values.back())
.is_none()
{
self.set_header_without_check(CONTENT_TYPE, default_content_type());
}
let is_event_stream: bool = self
.get_headers()
.get(CONTENT_TYPE)
.and_then(|values: &VecDeque<String>| values.back())
.is_some_and(|value: &String| value.eq_ignore_ascii_case(TEXT_EVENT_STREAM));
let compressed_body: Option<Vec<u8>> = match compress_type_opt {
Some(compress_type) if !compress_type.is_unknown() => Some(
compress_type
.encode(self.get_body(), DEFAULT_BUFFER_SIZE)
.into_owned(),
),
_ => None,
};
let body_len: usize = compressed_body
.as_ref()
.map_or_else(|| self.get_body().len(), Vec::len);
if !is_event_stream {
let mut digits: [u8; B_20] = [0; B_20];
let rendered: &str = render_length(body_len, &mut digits);
self.set_header_without_check(CONTENT_LENGTH, rendered);
}
let mut head_size: usize = self.get_reason_phrase().len() + B_16 + HTTP_BR.len();
head_size += self
.get_headers()
.iter()
.map(|header_entry: (&String, &VecDeque<String>)| {
let (header_key, header_values): (&String, &VecDeque<String>) = header_entry;
header_values
.iter()
.map(|header_value: &String| {
header_key.len() + COLON.len() + header_value.len() + HTTP_BR.len()
})
.sum::<usize>()
})
.sum::<usize>();
let mut response_bytes: Vec<u8> = Vec::with_capacity(head_size + body_len);
response_bytes.extend_from_slice(self.get_version().as_str().as_bytes());
response_bytes.push(b' ');
let mut code: [u8; B_20] = [0; B_20];
response_bytes
.extend_from_slice(render_length(self.get_status_code(), &mut code).as_bytes());
response_bytes.push(b' ');
response_bytes.extend_from_slice(self.get_reason_phrase().as_bytes());
response_bytes.extend_from_slice(HTTP_BR.as_bytes());
self.get_headers()
.iter()
.for_each(|header_entry: (&String, &VecDeque<String>)| {
let (header_key, header_values): (&String, &VecDeque<String>) = header_entry;
for header_value in header_values.iter() {
Self::push_header(&mut response_bytes, header_key, header_value);
}
});
response_bytes.extend_from_slice(HTTP_BR.as_bytes());
match &compressed_body {
Some(body) => response_bytes.extend_from_slice(body),
None => response_bytes.extend_from_slice(self.get_body()),
}
response_bytes
}
}