use std::fmt::{Display, Formatter};
use crate::errors::ServerError;
use crate::ext::hash_map_ext::HashMapExt;
use crate::types::headers::Headers;
use crate::types::protocol::Protocol;
use crate::types::status::HttpStatus;
pub type ServerResponse = Result<HttpResponse, ServerError>;
#[derive(Clone, Debug, Default)]
pub struct HttpResponse {
protocol: Protocol,
status: HttpStatus,
body: Vec<u8>,
headers: Headers,
}
impl HttpResponse {
#[must_use]
pub fn from_error(e: &ServerError, protocol: Protocol) -> Self {
let (status, body) = match e {
ServerError::BadRequest { .. } | ServerError::ParseError { .. } => {
(HttpStatus::BadRequest, "Bad request")
}
ServerError::EmptyRequest => (HttpStatus::BadRequest, "Empty request"),
ServerError::InternalError { .. } => {
(HttpStatus::InternalServerError, "Internal error")
}
ServerError::IoError { .. } => (HttpStatus::InternalServerError, "IO error"),
ServerError::NotFound { .. } => (HttpStatus::NotFound, "Not Found"),
ServerError::Unauthorized => (HttpStatus::Unauthorized, "Unauthorized"),
ServerError::UnsupportedRequestType => {
(HttpStatus::MethodNotAllowed, "Unsupported request type")
}
};
let mut headers = Headers::default();
headers.insert("Content-length", &body.len().to_string());
Self {
protocol,
status,
body: body.as_bytes().to_vec(),
headers,
}
}
#[must_use]
pub fn append_default_headers(mut self) -> Self {
self.headers
.insert_if_not_exists("Content-Length", &self.body.len().to_string());
self.headers
.insert_if_not_exists("Content-Type", "text/plain; charset=utf-8");
self.headers
.insert_if_not_exists("Date", &chrono::Utc::now().to_rfc2822());
self.clone()
}
}
pub trait HttpResponseData {
fn protocol(&mut self, value: Protocol) -> ServerResponse;
fn status(&mut self, value: HttpStatus) -> ServerResponse;
fn body(&mut self, value: &[u8]) -> ServerResponse;
fn headers(&mut self, value: Headers) -> ServerResponse;
fn header(&mut self, k: &str, v: &str) -> ServerResponse;
}
impl HttpResponseData for HttpResponse {
fn protocol(&mut self, value: Protocol) -> ServerResponse {
self.protocol = value;
Ok(self.clone())
}
fn status(&mut self, value: HttpStatus) -> ServerResponse {
self.status = value;
Ok(self.clone())
}
fn body(&mut self, value: &[u8]) -> ServerResponse {
self.body = value.to_vec();
Ok(self.clone())
}
fn headers(&mut self, value: Headers) -> ServerResponse {
self.headers = value;
Ok(self.clone())
}
fn header(&mut self, k: &str, v: &str) -> ServerResponse {
self.headers.insert(k, v);
Ok(self.clone())
}
}
impl HttpResponseData for ServerResponse {
fn protocol(&mut self, value: Protocol) -> ServerResponse {
self.clone()?.protocol(value)
}
fn status(&mut self, value: HttpStatus) -> ServerResponse {
self.clone()?.status(value)
}
fn body(&mut self, value: &[u8]) -> ServerResponse {
self.clone()?.body(value)
}
fn headers(&mut self, value: Headers) -> ServerResponse {
self.clone()?.headers(value)
}
fn header(&mut self, k: &str, v: &str) -> ServerResponse {
self.clone()?.header(k, v)
}
}
impl Display for HttpResponse {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut errors = vec![];
errors.push(write!(f, "{} {}", self.protocol, self.status));
if !self.headers.is_empty() {
errors.push(write!(f, "\r\n{}", self.headers));
}
if !self.body.is_empty() {
errors.push(write!(
f,
"\r\n\r\n{}",
String::from_utf8(self.body.clone()).unwrap()
));
}
if errors.is_empty() {
Ok(())
} else {
errors[0]
}
}
}