df_helper/http/
web.rs

1use std::io::{Read, Write};
2use std::net::{TcpListener, TcpStream};
3use std::thread;
4use json::{array, JsonValue, object};
5use crate::cryptos;
6use crate::datetime::datetime;
7use crate::datetime::timestamp::timestamp;
8use crate::files::file::{file_content_get_stream, file_content_put, is_file, remove};
9use crate::tools::string;
10
11
12/// 跨域
13pub struct Cors {
14    allow_origin: String,
15    allow_methods: String,
16    allow_headers: String,
17    allow_credentials: bool,
18    max_age: i32,
19}
20
21impl Cors {
22    /// 默认
23    pub fn default() -> Self {
24        Self {
25            allow_origin: "*".to_string(),
26            allow_methods: "*".to_string(),
27            allow_headers: "*".to_string(),
28            allow_credentials: true,
29            max_age: 0,
30        }
31    }
32    /// 设置限制域名
33    pub fn allow_origin(mut self, origin: &str) -> Self {
34        self.allow_origin = origin.to_string();
35        self
36    }
37
38    /// 设置请求类型
39    pub fn allow_methods(mut self, methods: &str) -> Self {
40        self.allow_methods = methods.to_string();
41        self
42    }
43    /// 设置请求头允许的字段
44    pub fn allow_headers(mut self, headers: &str) -> Self {
45        self.allow_headers = headers.to_string();
46        self
47    }
48    /// 设置请求头允许Cookie
49    pub fn allow_credentials(mut self, open: bool) -> Self {
50        self.allow_credentials = open;
51        self
52    }
53    /// 设置缓存周期
54    pub fn max_age(mut self, int: i32) -> Self {
55        self.max_age = int;
56        self
57    }
58}
59
60/// 响应
61struct Response {
62    stream: TcpStream,
63    public: String,
64    header: JsonValue,
65    get: JsonValue,
66    post: JsonValue,
67    files: JsonValue,
68    cors: Cors,
69}
70
71impl Response {
72    /// 默认
73    pub fn default(stream: TcpStream, cors: JsonValue, public: String) -> Self {
74        let cors = Cors::default()
75            .allow_origin(cors["allow_origin"].as_str().unwrap())
76            .allow_methods(cors["allow_methods"].as_str().unwrap())
77            .allow_headers(cors["allow_headers"].as_str().unwrap())
78            .allow_credentials(cors["allow_credentials"].as_bool().unwrap())
79            .max_age(cors["max_age"].as_i32().unwrap());
80        Self {
81            stream,
82            public,
83            header: object! {},
84            get: object! {},
85            post: object! {},
86            files: object! {},
87            cors,
88        }
89    }
90    /// 监听
91    pub fn handle(&mut self, fun: fn(response: JsonValue) -> (JsonValue, i32, String)) {
92        let mut buf: Vec<u8> = vec![];
93        // 第一次加载
94        let mut buffer = [0; 1024];
95        let count = self.stream.read(&mut buffer).unwrap();
96        buf = [buf, buffer[0..count].to_vec()].concat();
97        let data_length = buf.len();
98        self._header(buf.clone());
99
100        // 判断是否检查请求
101        if self.header["method"].as_str().unwrap() == "OPTIONS" {
102            self._options();
103            return;
104        }
105        // 检查是否是文件路径
106        let file = format!("{}{}", self.public, self.header["uri"].as_str().unwrap());
107        if is_file(file.as_str()) {
108            self._file_html(file.as_str());
109            return;
110        }
111        let body_length = self.header["content-length"].as_usize().unwrap();
112        let header_length = self.header["header_length"].as_usize().unwrap();
113        let mut mun = data_length - header_length;
114        // 检查是否完整
115        while mun < body_length {
116            let mut buffer = [0; 1024];
117            let count = self.stream.read(&mut buffer).unwrap();
118            mun += count;
119            buf = [buf, buffer[0..count].to_vec()].concat();
120        };
121        let body = buf[header_length..].to_owned();
122        self._body(body.clone());
123
124        let response = object! {
125            header:self.header.clone(),
126            post:self.post.clone(),
127            get:self.get.clone(),
128            files:self.files.clone()
129        };
130        let (contents, code, content_type) = fun(response);
131        self.write(contents, code, content_type);
132        // 清理temp临时缓存文件
133        for (_, files) in self.files.entries_mut() {
134            for item in files.members() {
135                if is_file(item["temp"].as_str().unwrap()) {
136                    // println!("删除文件:{}", item["temp"]);
137                    remove(item["temp"].as_str().unwrap());
138                }
139            }
140        }
141    }
142    /// 头部信息处理
143    fn _header(&mut self, data: Vec<u8>) {
144        let data = String::from_utf8(data.to_vec()).unwrap();
145        let list = string::split(data, "\r\n\r\n");
146        let data = list[0].to_string();
147        let headers = string::split(data.clone(), "\r\n");
148        let list = string::split(headers[0].to_string(), " ");
149        self.header["header_length"] = (data.len() + 4).into();
150        self.header["method"] = list[0].clone();
151        self.header["uri"] = list[1].clone();
152        self.header["version"] = list[2].clone();
153        self._query(self.header["uri"].to_string());
154        for header in headers.members() {
155            let list = string::split(header.to_string(), ": ");
156            if list.len() == 2 {
157                self.header[list[0].to_string().to_lowercase().as_str()] = list[1].clone();
158                continue;
159            }
160        }
161        self.header["content-type"] = self._content_type(self.header["content-type"].to_string(), self.header["accept"].to_string()).into();
162        self.header["content-length"] = self.header["content-length"].to_string().parse::<i32>().unwrap_or(0).into();
163    }
164    /// 内容处理
165    fn _body(&mut self, data: Vec<u8>) {
166        match self.header["content-type"].as_str().unwrap() {
167            "multipart/form-data" => {
168                self._multipart(data.clone());
169            }
170            "application/x-www-form-urlencoded" => {
171                let text = String::from_utf8(data.clone()).unwrap();
172                let text = string::split(text.to_string(), "&");
173                for item in text.members() {
174                    let row = string::split(item.to_string(), "=");
175                    self.post[row[0].clone().as_str().unwrap()] = row[1].clone();
176                }
177            }
178            "application/json" => {
179                let text = String::from_utf8(data).unwrap();
180                let length = self.header["content-length"].to_string().parse::<usize>().unwrap();
181                if length == 0 {
182                    return;
183                }
184                self.post = json::parse(&*text.clone()).unwrap();
185            }
186            _ => {
187                // println!(">>>>>>> >>>>>>");
188                // println!("{}", data);
189                // println!(">>>>>>> >>>>>>");
190            }
191        }
192    }
193    /// 数据提取
194    fn _multipart(&mut self, data: Vec<u8>) {
195        let boundary = self.header["boundary"].as_str().unwrap();
196        let text = unsafe { String::from_utf8_unchecked(data.clone()) };
197        let text = text.trim_start_matches("\r\n");
198        let text = text.trim_end_matches(format!("\r\n--{}--\r\n", boundary.clone()).as_str()).to_string();
199
200        let fg = format!("--{}\r\n", boundary.clone());
201        let list = string::split(text.clone(), fg.as_str().clone());
202        let mut index = 0;
203        let mut body = data[2 + fg.len()..].to_vec();
204        while index < list.len() {
205            let item = list[index].to_string();
206            let item = item.trim_start_matches(boundary.clone());
207            let len = item.len();
208            if len == 0 {
209                index += 1;
210                continue;
211            }
212            let mode = string::search(item, "filename=");
213            match mode {
214                false => {
215                    let row = string::split(item.to_string(), "\r\n\r\n");
216                    let field = string::split(row[0].to_string(), "\"");
217                    let name = field[1].as_str().unwrap();
218                    let row = string::split(row[1].to_string(), "\r\n");
219                    let value = string::split(row[0].to_string(), "\"");
220                    let value = value[0].clone();
221                    self.post[name] = value.clone();
222                }
223                true => {
224                    let text = string::split(item.to_string(), "\r\n\r\n");
225                    let body = text[1].to_string();
226                    let file = body.as_str().trim_start_matches("\u{0}");
227                    let text = text[0].clone();
228                    let text = string::split(text.to_string(), "\r\n");
229                    let name = string::split(text[0].to_string(), "\"");
230                    let types = string::split(text[1].to_string(), ": ");
231                    let types = types[1].as_str().unwrap();
232                    let field = name[1].as_str().unwrap();
233                    let filename = name[3].as_str().unwrap();
234                    fn _content_type_mode(data: &str) -> String {
235                        match data {
236                            "image/png" => "png",
237                            "image/jpeg" => "jpeg",
238                            "image/jpg" => "jpg",
239                            _ => "txt"
240                        }.to_string().clone()
241                    }
242                    let mut file_data = object! {};
243                    file_data["type"] = types.into();
244                    file_data["name"] = filename.into();
245                    file_data["size"] = file.len().into();
246                    file_data["sha"] = cryptos::sha::to_sha1(file.clone()).into();
247                    file_data["mode"] = json::JsonValue::String(_content_type_mode(types.clone()).clone());
248                    let temp_file = format!("{}.{}", timestamp("ms").to_string(), file_data["mode"]);
249                    let filename = format!("{}/../temp/{}", self.public, temp_file);
250                    file_data["temp"] = filename.clone().into();
251                    file_content_put(&*filename, file.clone());
252                    if self.files[field].is_empty() {
253                        self.files[field] = array![file_data];
254                    } else {
255                        self.files[field].push(file_data).unwrap();
256                    }
257                }
258            }
259            index += 1;
260            if index == list.len() {} else {
261                body = body[len + fg.len()..].to_vec();
262            }
263        }
264    }
265
266    /// 请求类型
267    fn _content_type(&mut self, data: String, accept: String) -> String {
268        if string::search(data.to_lowercase().as_str(), "text/html") {
269            return "text/html".to_string();
270        }
271        if string::search(data.to_lowercase().as_str(), "text/xml") {
272            return "text/xml".to_string();
273        }
274        if string::search(data.to_lowercase().as_str(), "application/json") {
275            return "application/json".to_string();
276        }
277        if string::search(data.to_lowercase().as_str(), "multipart/form-data") {
278            let ttt = string::split(data, "boundary=");
279            self.header["boundary"] = ttt[1].clone();
280            return "multipart/form-data".to_string();
281        }
282        if string::search(data.to_lowercase().as_str(), "application/x-www-form-urlencoded") {
283            return "application/x-www-form-urlencoded".to_string();
284        }
285        if string::search(data.to_lowercase().as_str(), "text/plain") {
286            return "text/plain".to_string();
287        }
288        if data.is_empty() {
289            if string::search(accept.to_lowercase().as_str(), "image/*") {
290                return "image/*".to_string();
291            }
292            if string::search(accept.to_lowercase().as_str(), "image/webp") {
293                return "image/*".to_string();
294            }
295            if string::search(accept.to_lowercase().as_str(), "image/gif") {
296                return "image/gif".to_string();
297            }
298        }
299        // println!("请求类型:{}", data);
300        return "text/plain".to_string();
301    }
302    /// get参数处理
303    fn _query(&mut self, data: String) {
304        let query = string::split(data, "?");
305        let query = query[1].clone();
306        if query.is_empty() {
307            return;
308        }
309        let query = string::split(query.to_string(), "&");
310        let mut list = object! {};
311        for item in query.members() {
312            let row = string::split(item.to_string(), "=");
313            let key = row[0].clone();
314            let value = row[1].clone();
315            list[key.as_str().unwrap()] = value.into();
316        }
317        self.get = list;
318    }
319    /// 读取文件返回
320    fn _file_html(&mut self, filename: &str) {
321        let name = string::split(filename.to_string(), "/");
322        let name = name[name.len() - 1].as_str().unwrap();
323        let sufxx = string::split(filename.to_string(), ".");
324        let sufxx = sufxx[sufxx.len() - 1].as_str().unwrap();
325        let contents = file_content_get_stream(filename);
326        let crlf = "\r\n";
327        let status = format!("HTTP/1.1 200 OK{}", crlf);
328        let date = format!("Date: {}{}", datetime::to_gmt(), crlf);
329        let server = format!("Server: Rust{}", crlf);
330        let content_length = format!("Content-Length: {}{}", contents.len(), crlf);
331        let content_disposition = match sufxx {
332            "html" => {
333                format!("")
334            }
335            _ => {
336                format!("Content-Disposition: attachment; filename={}{}", name, crlf)
337            }
338        };
339        let content_type = match sufxx {
340            "jpg" => {
341                format!("content-type:image/jpg{}", crlf)
342            }
343            "png" => {
344                format!("content-type:image/png{}", crlf)
345            }
346            "bmp" => {
347                format!("content-type:image/bmp{}", crlf)
348            }
349            "jpeg" => {
350                format!("content-type:image/jpeg{}", crlf)
351            }
352            "svg" => {
353                format!("content-type:image/svg{}", crlf)
354            }
355            "webp" => {
356                format!("content-type:image/webp{}", crlf)
357            }
358            "ico" => {
359                format!("content-type:image/ico{}", crlf)
360            }
361            "gif" => {
362                format!("content-type:image/gif{}", crlf)
363            }
364            _ => {
365                format!("content-type: text/plain;charset=utf-8{}", crlf)
366            }
367        };
368        let response = format!("{}{}{}{}{}{}{}{}", status, date, server, content_disposition, content_type, content_length, crlf, contents);
369        self.stream.write_all(response.as_bytes()).unwrap();
370        self.stream.flush().unwrap();
371    }
372    fn _options(&mut self) {
373        let crlf = "\r\n";
374        let status = format!("HTTP/1.1 200 OK{}", crlf);
375        let date = format!("Date: {}{}", datetime::to_gmt(), crlf);
376        let server = format!("Server: Rust{}", crlf);
377        let allow_origin = format!("Access-Control-Allow-Origin: {}{}", self.cors.allow_origin, crlf);
378        let allow_methods = format!("Access-Control-Allow-Methods: {}{}", self.cors.allow_methods, crlf);
379        let allow_headers = format!("Access-Control-Allow-Headers: {}{}", self.cors.allow_headers, crlf);
380        let max_age = format!("Access-Control-Max-Age: {}{}", self.cors.max_age, crlf);
381        let allow_credentials = format!("Access-Control-Allow-Credentials: {}{}", self.cors.allow_credentials, crlf);
382
383        let response = format!("{}{}{}{}{}{}{}{}{}",
384                               status, date, server,
385                               allow_origin,
386                               allow_methods,
387                               allow_credentials,
388                               max_age,
389                               allow_headers,
390                               crlf);
391        self.stream.write(response.as_bytes()).unwrap();
392        self.stream.flush().unwrap();
393    }
394    /// 将响应写出到流
395    fn write(&mut self, contents: JsonValue, code: i32, content_type: String) {
396        let crlf = "\r\n";
397        let status = format!("HTTP/1.1 {} {}{}", code, "OK", crlf);
398        let content_type = {
399            match content_type.as_str() {
400                "json" => {
401                    format!("content-type: application/json;charset=utf-8{}", crlf)
402                }
403                _ => {
404                    format!("content-type: text/html;charset=utf-8{}", crlf)
405                }
406            }
407        };
408        let access_control_allow_origin = format!("Access-Control-Allow-Origin: *{}", crlf);
409        let content_length = format!("Content-Length: {}{}", contents.to_string().as_bytes().len(), crlf);
410        let response = format!("{}{}{}{}{}{}", status, content_type, access_control_allow_origin, content_length, crlf, contents);
411        self.stream.write(response.as_bytes()).unwrap();
412        self.stream.flush().unwrap();
413    }
414}
415
416pub struct Web {
417    ip: String,
418    /// 本地路径
419    public: String,
420}
421
422impl Web {
423    pub fn bind(ip: &str, public: &str) -> Self {
424        Self {
425            ip: ip.to_string(),
426            public: public.to_string(),
427        }
428    }
429    /// 运行
430    pub fn run(&mut self, cors: JsonValue, handle: fn(response: JsonValue) -> (JsonValue, i32, String)) {
431        let listener = TcpListener::bind(self.ip.as_str()).unwrap();
432        for stream in listener.incoming() {
433            let cors = cors.clone();
434            let public = self.public.clone();
435            let stream = stream.unwrap();
436            thread::spawn(move || Response::default(stream, cors, public).handle(handle));
437        }
438    }
439}