#[cfg(feature = "tera")]
use crate::template;
use crate::{settings, storage::cookie::Cookie};
use log::{error, warn};
#[cfg(feature = "tera")]
use tera::Context;
#[derive(Debug, Clone)]
pub struct Response {
status: String,
content_type: String,
location: String,
cookies: Vec<Cookie>,
content: String,
content_length: String,
}
impl Response {
pub fn new() -> Response {
Response {
status: "".to_string(),
content_type: "".to_string(),
location: "".to_string(),
cookies: Vec::new(),
content: "".to_string(),
content_length: "".to_string(),
}
}
pub fn set_status(mut self, status_code: i32) -> Self {
self.status = match status_code {
200 => "HTTP/1.1 200 OK".to_string(),
301 => "HTTP/1.1 301 Moved Permanently".to_string(),
302 => "HTTP/1.1 302 Found".to_string(),
403 => "HTTP/1.1 403 Forbidden".to_string(),
404 => "HTTP/1.1 404 Not Found".to_string(),
500 => "HTTP/1.1 500 Internal Server Error".to_string(),
503 => "HTTP/1.1 503 Service Unavailable".to_string(),
_ => "".to_string(),
};
self
}
pub fn set_content_type<'a>(mut self, content_type: &str) -> Self {
self.content_type = format!("\r\nContent-Type: {};", content_type);
self
}
pub fn set_location(mut self, url: &str) -> Self {
self.location = format!("\r\nLocation: {}", url);
self
}
pub fn add_cookie(&mut self, cookie: Cookie) -> &Self {
self.cookies.push(cookie);
self
}
pub fn add_session(mut self, session_name: &str, session_key_in_redis: String) -> Self {
match settings::get_string(&format!("session.{}.cookie", session_name)) {
Ok(cookie_name) => {
self.add_cookie(
Cookie::new()
.set_from_settings(&cookie_name)
.set_value(session_key_in_redis)
.clone(),
);
}
Err(e) => {
warn!("{}", e);
error!("Cookie could not be created.");
}
}
self
}
pub fn set_content(mut self, content: &str) -> Self {
self.content = format!("{}", content);
self
}
pub fn set_content_length(mut self, content_length: usize) -> Self {
self.content_length = format!("\r\nContent-Length: {}", content_length);
self
}
pub fn create(&self) -> Vec<u8> {
format!(
"{}{}{}{}\r\n\r\n{}",
self.status,
self.location,
self.create_cookies(),
self.content_type,
self.content
)
.as_bytes()
.to_vec()
}
fn create_cookies(&self) -> String {
let mut cookie_vec: Vec<String> = Vec::new();
for cookie in &self.cookies {
cookie_vec.push(cookie.create());
}
cookie_vec.join("")
}
}
pub fn json(contents: &str) -> Response {
Response::new()
.set_status(200)
.set_content_type("application/json; charset=UTF-8")
.set_content_length(contents.len())
.set_content(&contents)
}
pub fn xml(contents: &str) -> Response {
Response::new()
.set_status(200)
.set_content_type("application/xml; charset=UTF-8")
.set_content_length(contents.len())
.set_content(&contents)
}
pub fn redirect(url: String) -> Response {
Response::new().set_status(302).set_location(&url)
}
#[cfg(feature = "tera")]
pub fn render(filename: &str, parameters: Context) -> Response {
create_html_response(200, filename, parameters)
}
#[cfg(feature = "tera")]
pub fn error(status: i32, filename: &str, parameters: Context) -> Response {
create_html_response(status, filename, parameters)
}
#[cfg(feature = "tera")]
fn create_html_response(status: i32, filename: &str, parameters: Context) -> Response {
let contents = template::get_content(filename, parameters);
Response::new()
.set_status(status)
.set_content_type("text/html; charset=UTF-8")
.set_content_length(contents.len())
.set_content(&contents)
}
#[cfg(feature = "test")]
pub trait Mock {
fn mock_get_status(self) -> String;
fn mock_get_content_type(self) -> String;
fn mock_get_location(self) -> String;
fn mock_get_cookies(self) -> Vec<Cookie>;
fn mock_get_content(self) -> String;
fn mock_get_content_length(self) -> String;
}
#[cfg(feature = "test")]
impl Mock for Response {
fn mock_get_status(self) -> String {
self.status
}
fn mock_get_content_type(self) -> String {
self.content_type
}
fn mock_get_location(self) -> String {
self.location
}
fn mock_get_cookies(self) -> Vec<Cookie> {
self.cookies
}
fn mock_get_content(self) -> String {
self.content
}
fn mock_get_content_length(self) -> String {
self.content_length
}
}