df-web 0.1.28

This is an WEB SERVER
Documentation
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;


/// http请求
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());
        // // 清理temp临时缓存文件
        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);
        // self.stream.write_all(response.as_bytes()).unwrap();
        // self.stream.flush().unwrap();
        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)
    }
}