1use std::{fs};
2use std::fs::{remove_file};
3use std::path::Path;
4use chrono::{Utc};
5use json::{JsonValue, object};
6use log::info;
7use crate::cors::Cors;
8
9
10pub struct Http {
12 cors: Cors,
13}
14
15impl Http {
16 pub fn default(cors: Cors) -> Self {
17 Self {
18 cors: cors.clone(),
19 }
20 }
21 pub fn handle(&mut self, header: JsonValue, mut body: JsonValue, fun: fn(request: JsonValue) -> (i32, &'static str, JsonValue)) -> (bool, String) {
22
23
24 if header["method"].as_str().unwrap() == "OPTIONS" {
26 return (true, self._write(200, object! {}, ""));
27 }
28
29 let file = format!("{}{}", header["public"], header["uri"].as_str().unwrap());
31
32 if Path::new(file.as_str()).is_file() {
33 return (true, self._file_html(file.as_str()));
34 }
35
36 body["header"] = header.clone();
37 let (code, content_type, contents) = fun(body.clone());
38 for (_, files) in body["files"].entries() {
40 for item in files.members() {
41 if Path::new(item["temp"].as_str().unwrap()).is_file() {
42 match remove_file(item["temp"].as_str().unwrap()) {
43 Ok(_) => true,
44 Err(_) => {
45 info!("删除文件失败:{}", item["temp"]);
46 false
47 }
48 };
49 }
50 }
51 }
52
53 let data = self._write(code.clone(), contents.clone(), content_type.clone());
54 match content_type {
55 "download" => {
56 match remove_file(contents.as_str().unwrap()) {
57 Ok(_) => true,
58 Err(_) => {
59 info!("删除文件失败:{}",contents);
60 false
61 }
62 };
63 (true, data)
64 }
65 _ => {
66 (true, data)
67 }
68 }
69 }
70 fn _file_html(&mut self, filename: &str) -> String {
72 let name: Vec<&str> = filename.split("/").collect();
73 let name = name[name.len() - 1];
74 let sufxx: Vec<&str> = filename.split(".").collect();
75 let sufxx = sufxx[sufxx.len() - 1];
76
77 let file = fs::read(filename).unwrap();
78 let contents = unsafe { String::from_utf8_unchecked(file) };
79
80 let crlf = "\r\n";
81 let status = format!("HTTP/1.1 200 OK{}", crlf);
82
83
84 let date = format!("Date: {}{}", Utc::now().format("%a %d %b %Y %H:%M:%S GMT").to_string(), crlf);
85 let server = format!("Server: Rust{}", crlf);
86 let content_length = format!("Content-Length: {}{}", contents.len(), crlf);
87 let content_disposition = match sufxx {
88 "html" => {
89 format!("")
90 }
91 _ => {
92 format!("Content-Disposition: attachment; filename={}{}", name, crlf)
93 }
94 };
95 let content_type = match sufxx {
96 "jpg" => {
97 format!("content-type:image/jpg{}", crlf)
98 }
99 "png" => {
100 format!("content-type:image/png{}", crlf)
101 }
102 "bmp" => {
103 format!("content-type:image/bmp{}", crlf)
104 }
105 "jpeg" => {
106 format!("content-type:image/jpeg{}", crlf)
107 }
108 "svg" => {
109 format!("content-type:image/svg{}", crlf)
110 }
111 "webp" => {
112 format!("content-type:image/webp{}", crlf)
113 }
114 "ico" => {
115 format!("content-type:image/ico{}", crlf)
116 }
117 "gif" => {
118 format!("content-type:image/gif{}", crlf)
119 }
120 _ => {
121 format!("content-type: text/plain;charset=utf-8{}", crlf)
122 }
123 };
124 let response = format!("{}{}{}{}{}{}{}{}", status, date, server, content_disposition, content_type, content_length, crlf, contents);
125 response
128 }
129
130 fn _write(&mut self, code: i32, contents: JsonValue, content_type: &str) -> String {
132 let crlf = "\r\n";
133 let mut list = vec![];
134
135 match code {
136 200 => {
137 list.push(format!("HTTP/1.1 {} {}", code, "OK"))
138 }
139 _ => {
140 list.push(format!("HTTP/1.1 {} {}", code, "Permanently Moved"))
141 }
142 };
143 list.push(format!("Date: {}", Utc::now().format("%a %d %b %Y %H:%M:%S GMT").to_string()));
144 list.push(format!("Connection: keep-alive"));
145
146 list.push(format!("Server: Rust"));
147 list.push(format!("Access-Control-Allow-Origin: {}", self.cors.allow_origin));
148 list.push(format!("Access-Control-Allow-Methods: {}", self.cors.allow_methods));
149 list.push(format!("Access-Control-Allow-Headers: {}", self.cors.allow_headers));
150 list.push(format!("Access-Control-Allow-Credentials: {}", self.cors.allow_credentials));
151
152 match content_type {
153 "json" => {
154 list.push(format!("Cache-Control: no-cache,max-age=0"));
155 list.push(format!("Content-type: application/json;charset=utf-8"))
156 }
157 "html" => {
158 list.push(format!("Access-Control-Max-Age: {}", self.cors.max_age));
159 list.push(format!("Content-type: text/html;charset=utf-8"))
160 }
161 "url" => {
162 list.push(format!("Cache-control: no-cache"));
163 list.push(format!("Content-Type: text/html;"))
164 }
165 "download" => {
166 list.push(format!("Cache-Control: no-cache,max-age=0"));
167 list.push(format!("Content-type: application/octet-stream"));
168 let path = contents.to_string();
169 let filename: Vec<&str> = path.split("/").collect();
170 let filename = filename[filename.len() - 1];
171 list.push(format!("Content-disposition: attachment; filename={}", filename))
172 }
173 _ => {
174 list.push(format!("Cache-Control: no-cache,max-age=0"));
175 list.push(format!("Content-type: text/html;charset=utf-8"))
176 }
177 }
178
179 match code {
180 200 => {
181 match content_type {
182 "download" => {
183 let file = fs::read(contents.to_string()).unwrap();
184 let contents = unsafe { String::from_utf8_unchecked(file) };
185 list.push(format!("Content-Length: {}\r\n", contents.len()));
186 list.push(contents);
187 }
188 _ => {
189 list.push(format!("Content-Length: {}\r\n", contents.to_string().as_bytes().len()));
190 list.push(format!("{}", contents));
191 }
192 }
193 }
194 301 => {
195 list.push(format!("Location: {}", contents.to_string()))
196 }
197 _ => {}
198 }
199 list.join(crlf)
200 }
201}