use std::{fs};
use std::fs::{remove_file};
use std::path::Path;
use chrono::{Utc};
use json::{JsonValue, object};
use log::info;
use crate::cors::Cors;
pub struct Http {
cors: Cors,
}
impl Http {
pub fn default(cors: Cors) -> Self {
Self {
cors: cors.clone(),
}
}
pub fn handle(&mut self, header: JsonValue, mut body: JsonValue, fun: fn(request: JsonValue) -> (i32, &'static str, JsonValue)) -> (bool, String) {
if header["method"].as_str().unwrap() == "OPTIONS" {
return (true, self._write(200, object! {}, ""));
}
let file = format!("{}{}", header["public"], header["uri"].as_str().unwrap());
if Path::new(file.as_str()).is_file() {
return (true, self._file_html(file.as_str()));
}
body["header"] = header.clone();
let (code, content_type, contents) = fun(body.clone());
for (_, files) in body["files"].entries() {
for item in files.members() {
if Path::new(item["temp"].as_str().unwrap()).is_file() {
match remove_file(item["temp"].as_str().unwrap()) {
Ok(_) => true,
Err(_) => {
info!("删除文件失败:{}", item["temp"]);
false
}
};
}
}
}
let data = self._write(code.clone(), contents.clone(), content_type.clone());
match content_type {
"download" => {
match remove_file(contents.as_str().unwrap()) {
Ok(_) => true,
Err(_) => {
info!("删除文件失败:{}",contents);
false
}
};
(true, data)
}
_ => {
(true, data)
}
}
}
fn _file_html(&mut self, filename: &str) -> String {
let name: Vec<&str> = filename.split("/").collect();
let name = name[name.len() - 1];
let sufxx: Vec<&str> = filename.split(".").collect();
let sufxx = sufxx[sufxx.len() - 1];
let file = fs::read(filename).unwrap();
let contents = unsafe { String::from_utf8_unchecked(file) };
let crlf = "\r\n";
let status = format!("HTTP/1.1 200 OK{}", crlf);
let date = format!("Date: {}{}", Utc::now().format("%a %d %b %Y %H:%M:%S GMT").to_string(), crlf);
let server = format!("Server: Rust{}", crlf);
let content_length = format!("Content-Length: {}{}", contents.len(), crlf);
let content_disposition = match sufxx {
"html" => {
format!("")
}
_ => {
format!("Content-Disposition: attachment; filename={}{}", name, crlf)
}
};
let content_type = match sufxx {
"jpg" => {
format!("content-type:image/jpg{}", crlf)
}
"png" => {
format!("content-type:image/png{}", crlf)
}
"bmp" => {
format!("content-type:image/bmp{}", crlf)
}
"jpeg" => {
format!("content-type:image/jpeg{}", crlf)
}
"svg" => {
format!("content-type:image/svg{}", crlf)
}
"webp" => {
format!("content-type:image/webp{}", crlf)
}
"ico" => {
format!("content-type:image/ico{}", crlf)
}
"gif" => {
format!("content-type:image/gif{}", crlf)
}
_ => {
format!("content-type: text/plain;charset=utf-8{}", crlf)
}
};
let response = format!("{}{}{}{}{}{}{}{}", status, date, server, content_disposition, content_type, content_length, crlf, contents);
response
}
fn _write(&mut self, code: i32, contents: JsonValue, content_type: &str) -> String {
let crlf = "\r\n";
let mut list = vec![];
match code {
200 => {
list.push(format!("HTTP/1.1 {} {}", code, "OK"))
}
_ => {
list.push(format!("HTTP/1.1 {} {}", code, "Permanently Moved"))
}
};
list.push(format!("Date: {}", Utc::now().format("%a %d %b %Y %H:%M:%S GMT").to_string()));
list.push(format!("Connection: keep-alive"));
list.push(format!("Server: Rust"));
list.push(format!("Access-Control-Allow-Origin: {}", self.cors.allow_origin));
list.push(format!("Access-Control-Allow-Methods: {}", self.cors.allow_methods));
list.push(format!("Access-Control-Allow-Headers: {}", self.cors.allow_headers));
list.push(format!("Access-Control-Allow-Credentials: {}", self.cors.allow_credentials));
match content_type {
"json" => {
list.push(format!("Cache-Control: no-cache,max-age=0"));
list.push(format!("Content-type: application/json;charset=utf-8"))
}
"html" => {
list.push(format!("Access-Control-Max-Age: {}", self.cors.max_age));
list.push(format!("Content-type: text/html;charset=utf-8"))
}
"url" => {
list.push(format!("Cache-control: no-cache"));
list.push(format!("Content-Type: text/html;"))
}
"download" => {
list.push(format!("Cache-Control: no-cache,max-age=0"));
list.push(format!("Content-type: application/octet-stream"));
let path = contents.to_string();
let filename: Vec<&str> = path.split("/").collect();
let filename = filename[filename.len() - 1];
list.push(format!("Content-disposition: attachment; filename={}", filename))
}
_ => {
list.push(format!("Cache-Control: no-cache,max-age=0"));
list.push(format!("Content-type: text/html;charset=utf-8"))
}
}
match code {
200 => {
match content_type {
"download" => {
let file = fs::read(contents.to_string()).unwrap();
let contents = unsafe { String::from_utf8_unchecked(file) };
list.push(format!("Content-Length: {}\r\n", contents.len()));
list.push(contents);
}
_ => {
list.push(format!("Content-Length: {}\r\n", contents.to_string().as_bytes().len()));
list.push(format!("{}", contents));
}
}
}
301 => {
list.push(format!("Location: {}", contents.to_string()))
}
_ => {}
}
list.join(crlf)
}
}