use crate::common;
use std::{
collections::HashMap,
io::{Read, Write},
};
pub(crate) struct Response {
pub status_code: u16,
pub version: String,
pub headers: HashMap<String, String>,
pub status_line: String,
pub body: Option<Vec<u8>>,
pub mime: Option<String>,
}
impl Response {
pub(crate) fn new() -> Response {
Response {
version: "HTTP/1.1".to_string(),
status_code: 404,
headers: HashMap::new(),
status_line: String::new(),
body: None,
mime: None,
}
}
pub fn header_set(&mut self, k: &str, v: &str) -> &mut Self {
self.headers.insert(k.to_string(), v.to_string());
self
}
pub fn status(&mut self, code: u16) -> &Self {
self.status_code = code;
self
}
pub fn status_line<P: Into<String>>(&mut self, line: P) -> &mut Self {
self.status_line = line.into();
self
}
pub fn body(&mut self, body: Vec<u8>) -> &Self {
let cl = format!("{}", body.len());
self.body = Some(body);
self.headers.insert("Content-Length".to_owned(), cl);
self
}
pub fn mime<P>(&mut self, mime: P) -> &mut Self
where
P: Into<String>,
{
let ct = mime.into();
self.mime = Some(ct.clone());
self.headers.insert("Content-Type".to_owned(), ct);
self.headers.insert("Server".to_owned(), "Rust/Zing/felix".to_string());
self
}
pub fn send<P: Read + Write>(&self, sock: &mut P) {
write!(sock, "{} \r\n", self.status_line).unwrap();
for (k, v) in self.headers.iter() {
write!(sock, "{}: {}\r\n", k, v).unwrap();
}
write!(sock, "Date: {}\r\n", common::HTTPDate::new().to_string()).unwrap();
write!(sock, "Connection: {}\r\n", "close").unwrap();
let br = b"\r\n".as_slice();
sock.write(br).unwrap();
if let Some(data) = &self.body {
sock.write(data.as_slice()).unwrap();
}
sock.flush().unwrap();
}
}