use std::{
io::Write,
collections::HashMap,
};
use crate::{
error::Error,
body::Body,
StatusInfo, GeneralInfo,
};
impl Into<Vec<u8>> for StatusInfo {
fn into(self) -> Vec<u8> {
match self {
StatusInfo::Response(code, reason) => {
let mut head = vec![];
writeln!(head, "HTTP/1.1 {} {}\r", code, reason).unwrap();
head
},
_ => vec![],
}
}
}
impl Into<Vec<u8>> for GeneralInfo {
fn into(self) -> Vec<u8> {
let mut head = vec![];
head.extend::<Vec<u8>>(self.status.into());
for (k, v) in &self.headers {
writeln!(head, "{}: {}\r", k, v).unwrap();
}
head
}
}
#[derive(Debug)]
pub struct ServerResponse {
pub info: GeneralInfo,
pub body: Option<Body>,
pub compression_level: Option<u32>,
pub chunk_size: Option<usize>,
}
impl Into<Vec<u8>> for ServerResponse {
fn into(self) -> Vec<u8> {
let mut resp_data = vec![];
resp_data.extend::<Vec<u8>>(self.info.into());
writeln!(resp_data, "\r").unwrap();
if let Some(body) = self.body {
resp_data.extend::<Vec<u8>>(body.into());
}
resp_data
}
}
impl ServerResponse {
pub fn new(status: i32) -> Result<ServerResponse, Error> {
let reason = match status {
100 => "Continue",
101 => "Switching Protocols",
103 => "Early Hints",
200 => "OK",
201 => "Created",
202 => "Accepted",
203 => "Non-Authoritative Information",
204 => "No Content",
205 => "Reset Content",
206 => "Partial Content",
300 => "Multiple Choices",
301 => "Moved Permanently",
302 => "Found",
303 => "See Other",
304 => "Not Modified",
305 => "Use Proxy",
306 => "Switch Proxy",
307 => "Temporary Redirect",
308 => "Permanent Redirect",
400 => "Bad Request",
401 => "Unauthorized",
402 => "Payment Required",
403 => "Forbidden",
404 => "Not Found",
405 => "Method Not Allowed",
406 => "Not Acceptable",
407 => "Proxy Authentication Required",
408 => "Request Timeout",
409 => "Conflict",
410 => "Gone",
411 => "Length Required",
412 => "Precondition Failed",
413 => "Payload Too Large",
414 => "URI Too Long",
415 => "Unsupported Media Type",
416 => "Range Not Satisfiable",
417 => "Expectation Failed",
418 => "I'm a teapot",
421 => "Misdirected Request",
425 => "Too Early",
426 => "Upgrade Required",
428 => "Precondition Required",
429 => "Too Many Requests",
431 => "Request Header Fields Too Large",
451 => "Unavailable For Legal Reasons",
500 => "Internal Server Error",
501 => "Not Implemented",
502 => "Bad Gateway",
503 => "Service Unavailable",
504 => "Gateway Timeout",
505 => "HTTP Version Not Supported",
506 => "Variant Also Negotiates",
510 => "Not Extended",
511 => "Network Authentication Required",
_ => return Err(Error::HTTPStatusCodeNotRecognized),
};
Ok(ServerResponse {
info: GeneralInfo {
status: StatusInfo::Response(status, reason.into()),
headers: HashMap::new(),
},
body: None,
compression_level: None,
chunk_size: None,
})
}
pub fn set_header<S: Into<String>>(mut self, key: S, value: S) -> ServerResponse {
self.info.headers.insert(key.into(), value.into());
self
}
pub fn set_body<B: Into<Body>>(mut self, body: B) -> ServerResponse {
let body = body.into();
match body {
#[cfg(feature = "json")]
Body::Json(_) => {
self.info.headers.insert("Content-Type".into(), "application/json;charset=UTF-8".into());
},
_ => {
self.info.headers.insert("Content-Type".into(), "text/plain;".into());
},
}
self.body = Some(body);
self
}
pub fn set_chunk_size(mut self, chunk_size: usize) -> ServerResponse {
self.chunk_size = Some(chunk_size);
self
}
#[cfg(feature = "compress")]
pub fn set_compression_level(mut self, level: u32) -> ServerResponse {
self.compression_level = Some(level);
self
}
}