use std::collections::BTreeMap;
use std::convert::AsRef;
#[derive(Clone, Default, Debug)]
pub struct ResponseData<'a> {
pub status: &'a str,
pub headers: BTreeMap<&'a str, &'a str>,
}
impl<'a> ResponseData<'a> {
pub fn new() -> Self {
Self {
status: "200 OK",
headers: BTreeMap::new(),
}
}
pub fn set_status(mut self, status: &'a str) -> Self {
self.status = status;
self
}
}
pub fn respond(
content: impl AsRef<[u8]>,
content_type: impl AsRef<str>,
data: Option<ResponseData>,
) -> Vec<u8> {
let content = content.as_ref();
let data = match data {
Some(data) => data,
None => ResponseData::new(),
};
let status = data.status;
let mut headers = String::new();
data.headers.iter().for_each(|(k, v)| {
headers.push_str("\r\n");
headers.push_str(k);
headers.push_str(": ");
headers.push_str(v);
});
let mut response = Vec::new();
let header = format!(
"HTTP/1.1 {}\r\nserver: ltheinrich.de/lhi\r\ncontent-type: {}; charset=utf-8{}",
status,
content_type.as_ref(),
headers
);
response.extend_from_slice(header.as_bytes());
response.append(&mut set_content_length(content.len()));
response.extend_from_slice(content);
response.extend_from_slice(b"\r\n");
response
}
fn set_content_length(content_length: usize) -> Vec<u8> {
let mut header = Vec::new();
header.extend_from_slice(b"\r\n");
header.extend_from_slice(b"content-length: ");
header.extend_from_slice((content_length + 2).to_string().as_bytes());
header.extend_from_slice(b"\r\n\r\n");
header
}
pub fn redirect(url: impl AsRef<str>) -> Vec<u8> {
let url = url.as_ref();
let mut headers = BTreeMap::new();
headers.insert("location", url);
let data = ResponseData {
status: "303 See Other",
headers,
};
respond(
format!("<html><head><title>Moved</title></head><body><h1>Moved</h1><p><a href=\"{0}\">{0}</a></p></body></html>", url),
"text/html",
Some(data)
)
}