1use std::{fs, thread};
2use std::fs::OpenOptions;
3use std::io::Write;
4use std::str::Lines;
5use std::time::{Duration, UNIX_EPOCH};
6use chrono::{DateTime, Local};
7use json::{array, JsonValue, object};
8use log::{debug, error, info};
9use crate::config::Config;
10use crate::content_type::ContentType;
11
12#[derive(Clone, Debug)]
14pub struct Request {
15 pub config: Config,
16 pub protocol: Protocol,
18
19 pub method: Method,
21 pub uri: String,
23 pub app: String,
25
26 pub timestamp: f64,
28 pub datetime: String,
30
31 pub server_ip: String,
33 pub client_ip: String,
35 pub agent_ip: String,
37
38 pub origin: String,
40 pub host: String,
42 sec_fetch_dest: SecFetchDest,
44 sec_fetch_mode: SecFetchMode,
46 sec_fetch_site: SecFetchSite,
48 pub connection: Connection,
50 pub user_agent: String,
52 pub accept: String,
54 pub accept_encoding: String,
56 pub accept_language: String,
58 pub cache_control: String,
60 pub content_length: usize,
62 pub content_body_length: usize,
64 pub body: Vec<u8>,
66 pub referer: String,
68 pub content_type: RequestContentType,
70 pub boundary: String,
72 pub custom: JsonValue,
74 pub path: String,
76 pub query: String,
78 pub post: JsonValue,
79 pub text: String,
80 pub html: String,
81 pub get: JsonValue,
82
83 pub files: JsonValue,
84 pub authorization_mode: String,
86 pub authorization_user: String,
87 pub authorization_pass: String,
88 pub authorization_token: String,
89 pub authorization_data: String,
90 pub is_origin: bool,
92
93 pub upgrade: String,
95 pub sec_web_socket_key: String,
97 pub sec_web_socket_version: String,
99}
100
101impl Request {
102 pub fn new(config: Config, data: Vec<u8>) -> Result<Self, String> {
103 let (header, body) = if let Some(index) = data.windows(4).position(|window| window == [13, 10, 13, 10]) {
104 (data[..index].to_vec(), data[index + 4..].to_vec())
105 } else {
106 return Err("未找到消息头".to_string());
107 };
108 let header = unsafe { String::from_utf8_unchecked(header) };
109 if config.debug {
110 debug!("{:#}",header);
111 }
112 let mut data = header.lines();
113
114 let header_line = data.next().unwrap_or("");
115 let parts = header_line.split_whitespace().collect::<Vec<&str>>();
116 if parts.len() != 3 {
117 return Err(format!("非法请求: {}", header_line));
118 }
119
120
121 let method = Method::from(parts[0]);
122 let mut uri = br_crypto::encoding::urlencoding_decode(parts[1]);
123 if !uri.starts_with("/") {
124 uri = format!("/{}", uri.clone());
125 }
126 let protocol = Protocol::from(parts[2]);
127
128 let timestamp = Local::now().timestamp_millis() as f64 / 1000.0;
129 let d = UNIX_EPOCH + Duration::from_secs(timestamp as u64);
130 let datetime = DateTime::<Local>::from(d);
131 let datetime = datetime.format("%Y-%m-%d %H:%M:%S").to_string();
132
133 let mut request = Self {
134 config: config.clone(),
135 timestamp,
136 datetime,
137 protocol,
138 method,
139 uri,
140 server_ip: "".to_string(),
141 client_ip: "".to_string(),
142 agent_ip: "".to_string(),
143 origin: "".to_string(),
144 host: "".to_string(),
145 sec_fetch_dest: SecFetchDest::None,
146 sec_fetch_mode: SecFetchMode::None,
147 sec_fetch_site: SecFetchSite::None,
148 connection: Connection::None,
149 user_agent: "".to_string(),
150 accept: "".to_string(),
151 accept_encoding: "".to_string(),
152 accept_language: "".to_string(),
153 cache_control: "".to_string(),
154 content_length: 0,
155 content_body_length: body.len(),
156 body,
157 referer: "".to_string(),
158 content_type: RequestContentType::None,
159 boundary: "".to_string(),
160 custom: object! {},
161 path: "".to_string(),
162 query: "".to_string(),
163 post: object! {},
164 text: "".to_string(),
165 html: "".to_string(),
166 get: object! {},
167 files: object! {},
168 authorization_mode: "".to_string(),
169 authorization_user: "".to_string(),
170 authorization_pass: "".to_string(),
171 authorization_token: "".to_string(),
172 is_origin: false,
173 app: "".to_string(),
174 authorization_data: "".to_string(),
175 sec_web_socket_key: "".to_string(),
176 upgrade: "".to_string(),
177 sec_web_socket_version: "".to_string(),
178 };
179 request.header(data);
180 Ok(request)
181 }
182 pub fn json(&mut self) -> JsonValue {
183 let mut res = object! {};
184 res["protocol"] = self.protocol.str().into();
185 res["method"] = self.method.clone().str().into();
186 res["timestamp"] = self.timestamp.into();
187 res["datetime"] = self.datetime.clone().into();
188
189 res["schema"] = self.config.schema.clone().into();
190 res["domain"] = self.config.url.clone().into();
192 res["url"] = self.config.url.clone().into();
193
194 res["uri"] = self.uri.clone().into();
195 res["app"] = self.app.clone().into();
196
197 res["origin"] = self.origin.clone().into();
198 res["host"] = self.host.clone().into();
199 res["user_agent"] = self.user_agent.clone().into();
200 res["content_type"] = self.content_type.clone().str().into();
201 res["content_length"] = self.content_length.into();
202
203 res["server_ip"] = self.server_ip.clone().into();
204 res["client_ip"] = self.client_ip.clone().into();
205 res["agent_ip"] = self.agent_ip.clone().into();
206
207 res["path"] = self.path.clone().into();
208 res["query"] = self.query.clone().into();
209
210 res["custom"] = self.custom.clone();
211 res["post"] = self.post.clone();
212 res["get"] = self.get.clone();
213 res["text"] = self.text.clone().into();
214 res["html"] = self.html.clone().into();
215 res["files"] = self.files.clone();
216
217 res["authorization_mode"] = self.authorization_mode.clone().into();
218 res["authorization_user"] = self.authorization_user.clone().into();
219 res["authorization_pass"] = self.authorization_pass.clone().into();
220 res["authorization_token"] = self.authorization_token.clone().into();
221 res["authorization_data"] = self.authorization_data.clone().into();
222
223 res["public"] = self.config.public.clone().into();
224 res["runtime"] = self.config.runtime.clone().into();
225
226 if self.config.debug {
227 res["sec-fetch-dest"] = self.sec_fetch_dest.str().into();
228 res["sec-fetch-mode"] = self.sec_fetch_mode.str().into();
229 res["sec-fetch-site"] = self.sec_fetch_site.str().into();
230 res["accept-language"] = self.accept_language.clone().into();
231 res["connection"] = self.connection.str().into();
232 }
233 res
234 }
235 pub fn header(&mut self, data: Lines) -> &mut Self {
236 for text in data {
237 let (key, value) = match text.trim().find(":") {
238 None => {
239 continue;
240 }
241 Some(e) => {
242 let key = text[..e].trim().to_lowercase().clone();
243 let value = text[e + 1..].trim().to_string();
244 (key, value)
245 }
246 };
247 match key.as_str() {
248 "host" => self.host = value,
249 "sec-fetch-site" => self.sec_fetch_site = SecFetchSite::from(&value),
250 "sec-fetch-mode" => self.sec_fetch_mode = SecFetchMode::from(&value),
251 "sec-fetch-dest" => self.sec_fetch_dest = SecFetchDest::from(&value),
252 "connection" => self.connection = Connection::from(&value),
253 "user-agent" => self.user_agent = value,
254
255 "accept" => self.accept = value,
256 "accept-language" => {
257 let language = value.split(",").collect::<Vec<&str>>();
258 if language.len() > 1 {
259 self.accept_language = language[0].to_string();
260 } else {
261 self.accept_language = value;
262 }
263 }
264 "accept-encoding" => self.accept_encoding = value.split(",").collect::<Vec<&str>>().join(";"),
265
266 "cache-control" => self.cache_control = value,
267 "content-type" => {
268 match value {
269 _ if value.contains("multipart/form-data") => {
270 let boundary: Vec<&str> = value.split("boundary=").collect();
271 self.boundary = boundary[1..].join("").to_string();
272 self.content_type = RequestContentType::from("multipart/form-data");
273 }
274 _ => {
275 self.content_type = RequestContentType::from(value.as_str());
276 }
277 }
278 }
279 "content-length" => self.content_length = value.parse::<usize>().unwrap_or(0),
280 "origin" => self.origin = value,
281 "referer" => self.referer = value,
282 "authorization" => {
283 let authorization = value.split_whitespace().collect::<Vec<&str>>();
284 self.authorization_mode = authorization[0].to_lowercase();
285 match self.authorization_mode.as_str() {
286 "basic" => {
287 let text = br_crypto::base64::decode(authorization[1]);
288 let text: Vec<&str> = text.split(":").collect();
289 self.authorization_user = text[0].to_string();
290 self.authorization_pass = text[1].to_string();
291 }
292 "bearer" => {
293 self.authorization_token = authorization[1].to_string();
294 }
295 _ => {
296 self.authorization_data = authorization[1..].concat();
297 }
298 }
299 }
300 "sec-websocket-key" => {
301 self.sec_web_socket_key = value;
302 }
303 "sec_websocket_version" => {
304 self.sec_web_socket_version = value;
305 }
306 "upgrade" => {
307 self.upgrade = value;
308 }
309 _ => {
310 if !key.starts_with("x-") {
311 continue;
312 }
313 match &key[2..] {
314 "real-ip" => {
315 self.client_ip = value;
316 }
317 "forwarded-for" => {
319 self.agent_ip = value;
320 }
321 _ => {
322 self.custom[&key[2..]] = value.into();
323 }
324 }
325 }
326 }
327 }
328 self.query();
329 self
330 }
331 fn query(&mut self) {
332 let mut uri = self.uri.clone();
333 match uri.find("?") {
334 None => {}
335 Some(e) => {
336 let query = uri[e + 1..].to_string();
337 uri = uri[..e].to_string();
338 self.query = query.clone();
339 let params = if query.contains("&") {
340 query.split("&").collect::<Vec<&str>>()
341 } else {
342 vec![query.as_str()]
343 };
344 for param in params {
345 let res = param.split("=").collect::<Vec<&str>>();
346 let key = res[0];
347 let value = res[1..].concat();
348 let key = br_crypto::encoding::urlencoding_decode(key);
349 let value = br_crypto::encoding::urlencoding_decode(value.as_str());
350 self.get[key] = value.into();
351 }
352 }
353 }
354 self.path = uri.clone();
355 let apps = self.path.split("/").collect::<Vec<&str>>();
356 self.app = if !apps.is_empty() {
357 apps[1].to_string()
358 } else {
359 "api".to_string()
360 };
361 }
362 pub(crate) fn record_log(&mut self) {
364 let text = format!("[{}] client-ip: {} agent_ip: {} content-type: {} content-length: {} {} {} {}\r\n",
365 self.datetime.clone(),
366 self.client_ip.clone(),
367 self.agent_ip.clone(),
368 self.content_type.clone().str(),
369 self.content_length.clone(),
370 self.method.clone().str(), self.protocol.str(), self.uri
371 );
372 let dir_path = format!("{}/log/{}", self.config.runtime, self.datetime[0..10].replace("-", "/"));
373 let path = format!("{}/{}.log", dir_path.clone(), &self.datetime[11..13]);
374 let debug = self.config.debug;
375 thread::spawn(move || {
376 let path_new = path.clone();
377 match fs::create_dir_all(dir_path.clone()) {
378 Ok(_) => {}
379 Err(e) => {
380 if debug {
381 return error!("创建日志目录失败: {} {}",dir_path.clone(),e.to_string());
382 }
383 return;
384 }
385 };
386 match OpenOptions::new()
387 .read(true)
388
389 .create(true)
390 .append(true)
391 .open(path_new.clone()) {
392 Ok(mut file) => {
393 let _ = file.write_all(text.as_bytes());
394 }
395 Err(_) => {
396 if debug {
397 error!("日志写入失败: {}",path_new.clone())
398 }
399 }
400 }
401 });
402 }
403 pub fn body(&mut self) -> Result<(), String> {
404 if self.content_length > self.content_body_length {
405 return Err(format!("消息长度错误: {}/{}", self.content_body_length, self.content_length));
406 }
407 match self.content_type {
408 RequestContentType::FormData => {
409 let request = unsafe { String::from_utf8_unchecked(self.body.clone()) };
410 let mut request = request.trim_end_matches(format!("--{}--\r\n", self.boundary).as_str()).split(format!("--{}\r\n", self.boundary).as_str()).collect::<Vec<&str>>();
411 request.remove(0);
412 for item in request.iter_mut() {
413 if item.contains("filename=") {
414 let text: Vec<&str> = item.split("\r\n\r\n").collect();
415 let temp = if text.len() > 2 {
416 text[1..].join("\r\n\r\n")
417 } else {
418 text[1].to_string()
419 };
420 let body = match temp.strip_suffix("\r\n") {
421 None => temp.as_str(),
422 Some(v) => v
423 };
424 let text: Vec<&str> = text[0].split("\r\n").collect();
425 let name: Vec<&str> = text[0].split("\"").collect();
426 let types: Vec<&str> = text[1].split(": ").collect();
427 let accept = types[1];
428 let field = name[1];
429 let filename = name[3];
430
431 let mut file_data = object! {};
432 file_data["accept"] = accept.into();
433 file_data["name"] = filename.into();
434 file_data["md5"] = br_crypto::hash::str_to_md5(body).into();
435 file_data["suffix"] = ContentType::from(accept).suffix.into();
436 file_data["types"] = ContentType::from_suffix(file_data["suffix"].as_str().unwrap()).suffix_type_name().into();
437 file_data["size"] = body.len().into();
438 file_data["data"] = br_crypto::base64::encode_file(body.as_bytes().into()).into();
439 if self.files[field].is_empty() {
440 self.files[field] = array![file_data.clone()];
441 } else {
442 self.files[field].push(file_data.clone()).unwrap();
443 }
444 } else {
445 let re = item.split("\r\n\r\n").collect::<Vec<&str>>();
446 let name = re[0].trim_end_matches("\"").split("name=\"").collect::<Vec<&str>>();
447 self.post[name[1]] = re[1].trim_end_matches("\r\n").into();
448 }
449 }
450 }
451 RequestContentType::FOrmUrlencoded => {
452 let request = unsafe { String::from_utf8_unchecked(self.body.clone()) };
453 let params = if request.contains("&") {
454 request.split("&").collect::<Vec<&str>>()
455 } else {
456 vec![request.as_str()]
457 };
458 for param in params {
459 let res = param.split("=").collect::<Vec<&str>>();
460 let key = res[0];
461 let value = res[1..].concat();
462 let key = br_crypto::encoding::urlencoding_decode(key);
463 let value = br_crypto::encoding::urlencoding_decode(value.as_str());
464 self.post[key] = value.into();
465 }
466 }
467 RequestContentType::Javascript => {
468 let request = unsafe { String::from_utf8_unchecked(self.body.clone()) };
469 if self.config.debug {
470 info!("Javascript: {}", request);
471 }
472 }
473 RequestContentType::Json => {
474 let request = unsafe { String::from_utf8_unchecked(self.body.clone()) };
475 match json::parse(request.as_str()) {
476 Ok(e) => {
477 self.post = e;
478 }
479 Err(_) => {
480 error!("解析json失败,请检查格式:{}", request);
481 self.post = object! {}
482 }
483 };
484 }
485 RequestContentType::Xml => {
486 let request = unsafe { String::from_utf8_unchecked(self.body.clone()) };
487 let res = br_xml::Xml::xml_json(request);
488 self.post = res;
489 }
490 RequestContentType::Text => {
491 let request = unsafe { String::from_utf8_unchecked(self.body.clone()) };
492 self.text = request;
493 }
494 RequestContentType::Html => {
495 let request = unsafe { String::from_utf8_unchecked(self.body.clone()) };
496 self.html = request;
497 }
498 RequestContentType::None => {
499 let request = unsafe { String::from_utf8_unchecked(self.body.clone()) };
500 if self.config.debug {
501 info!("RequestContentType 未知: {}", request);
502 }
503 }
504 }
505 Ok(())
506 }
507
508 pub(crate) fn allow_origin(&mut self) {
510 self.is_origin = false;
511 if !self.config.cors.allow_origin.is_empty() {
512 if self.origin.is_empty() {
513 for origin in &self.config.cors.allow_origin {
514 if self.client_ip.contains(origin) {
515 self.is_origin = true;
516 }
517 }
518 } else {
519 for origin in &self.config.cors.allow_origin {
520 if self.origin.contains(origin) {
521 self.is_origin = true;
522 }
523 }
524 }
525 } else {
526 self.is_origin = true;
527 }
528 }
529}
530
531#[derive(Clone, Debug)]
533enum SecFetchSite {
534 CrossSite,
536 SameOrigin,
538 None,
540}
541
542impl SecFetchSite {
543 pub fn from(name: &str) -> Self {
544 match name.to_lowercase().as_str() {
545 "none" => Self::None,
546 "cross-site" => Self::CrossSite,
547 "same-origin" => Self::SameOrigin,
548 _ => Self::None,
549 }
550 }
551 pub fn str(&mut self) -> &'static str {
552 match self {
553 SecFetchSite::CrossSite => "cross-site",
554 SecFetchSite::SameOrigin => "same-origin",
555 SecFetchSite::None => "none"
556 }
557 }
558}
559
560#[derive(Clone, Debug)]
562enum SecFetchMode {
563 Navigate,
565 SameOrigin,
567 NoCors,
569 Cors,
571 Websocket,
573 None,
575}
576
577impl SecFetchMode {
578 pub fn from(name: &str) -> Self {
579 match name.to_lowercase().as_str() {
580 "navigate" => Self::Navigate,
581 "same-origin" => Self::SameOrigin,
582 "no-cors" => Self::NoCors,
583 "cors" => Self::Cors,
584 "websocket" => Self::Websocket,
585 _ => Self::None,
586 }
587 }
588 pub fn str(&mut self) -> &'static str {
589 match self {
590 Self::Navigate => "navigate",
591 Self::SameOrigin => "same-origin",
592 Self::NoCors => "no-cors",
593 Self::Cors => "cors",
594 Self::Websocket => "websocket",
595 Self::None => ""
596 }
597 }
598}
599
600#[derive(Clone, Debug)]
602enum SecFetchDest {
603 Document,
605 Image,
607 Media,
609 Font,
611 Script,
613 Css,
615 Manifest,
617 Serviceworker,
619 None,
621}
622
623impl SecFetchDest {
624 pub fn from(name: &str) -> Self {
625 match name.to_lowercase().as_str() {
626 "document" => Self::Document,
627 "image" => Self::Image,
628 "media" => Self::Media,
629 "font" => Self::Font,
630 "script" => Self::Script,
631 "css" => Self::Css,
632 "manifest" => Self::Manifest,
633 "serviceworker" => Self::Serviceworker,
634 _ => Self::None,
635 }
636 }
637 pub fn str(&mut self) -> &'static str {
638 match self {
639 Self::Document => "document",
640 Self::Image => "image",
641 Self::Media => "media",
642 Self::Font => "font",
643 Self::Script => "script",
644 Self::Css => "css",
645 Self::Manifest => "manifest",
646 Self::Serviceworker => "serviceworker",
647 Self::None => ""
648 }
649 }
650}
651
652#[derive(Clone, Debug)]
654pub enum Protocol {
655 HTTP1_1,
656 HTTP2,
657 None,
658}
659
660impl Protocol {
661 pub fn from(name: &str) -> Self {
662 match name.to_lowercase().as_str() {
663 "http/1.1" => Self::HTTP1_1,
664 "http/2" => Self::HTTP2,
665 _ => Self::None,
666 }
667 }
668 pub fn str(&mut self) -> &'static str {
669 match self {
670 Protocol::HTTP1_1 => "HTTP/1.1",
671 Protocol::HTTP2 => "HTTP/2",
672 Protocol::None => ""
673 }
674 }
675}
676
677#[derive(Clone, Debug)]
679pub enum Connection {
680 KeepAlive,
682 Close,
684 Upgrade,
685 None,
686}
687
688impl Connection {
689 pub fn from(name: &str) -> Self {
690 match name.to_lowercase().as_str() {
691 "keep-alive" => Self::KeepAlive,
692 "close" => Self::Close,
693 "upgrade" => Self::Upgrade,
694 _ => Self::None,
695 }
696 }
697 pub fn str(&mut self) -> &'static str {
698 match self {
699 Self::KeepAlive => "keep-alive",
700 Self::Close => "close",
701 Self::Upgrade => "upgrade",
702 Self::None => ""
703 }
704 }
705}
706
707#[derive(Clone, Debug)]
709pub enum Method {
710 POST,
711 GET,
712 HEAD,
713 PUT,
714 DELETE,
715 OPTIONS,
716 PATCH,
717 TRACE,
718 None,
719}
720
721impl Method {
722 pub fn from(name: &str) -> Self {
723 match name.to_lowercase().as_str() {
724 "post" => Self::POST,
725 "get" => Self::GET,
726 "head" => Self::HEAD,
727 "put" => Self::PUT,
728 "delete" => Self::DELETE,
729 "options" => Self::OPTIONS,
730 "patch" => Self::PATCH,
731 "trace" => Self::TRACE,
732 _ => Self::None,
733 }
734 }
735 pub fn str(self) -> &'static str {
736 match self {
737 Method::POST => "post",
738 Method::GET => "get",
739 Method::HEAD => "head",
740 Method::PUT => "put",
741 Method::DELETE => "delete",
742 Method::OPTIONS => "options",
743 Method::PATCH => "patch",
744 Method::TRACE => "trace",
745 Method::None => ""
746 }
747 }
748}
749
750#[derive(Clone, Debug)]
751pub enum RequestContentType {
752 FormData,
753 FOrmUrlencoded,
754 Json,
755 Xml,
756 Javascript,
757 Text,
758 Html,
759 None,
760}
761
762impl RequestContentType {
763 pub fn from(name: &str) -> Self {
764 match name {
765 "multipart/form-data" => Self::FormData,
766 "application/x-www-form-urlencoded" => Self::FOrmUrlencoded,
767 "application/json" => Self::Json,
768 "application/xml" | "text/xml" => Self::Xml,
769 "application/javascript" => Self::Javascript,
770 "text/html" => Self::Html,
771 "text/plain" => Self::Text,
772 _ => {
773 info!("未知请求类型: {}", name);
774 Self::None
775 }
776 }
777 }
778 pub fn str(self) -> &'static str {
779 match self {
780 RequestContentType::FormData => "multipart/form-data",
781 RequestContentType::FOrmUrlencoded => "application/x-www-form-urlencoded",
782 RequestContentType::Json => "application/json",
783 RequestContentType::Xml => "application/xml",
784 RequestContentType::Javascript => "application/javascript",
785 RequestContentType::Text => "text/plain",
786 RequestContentType::Html => "text/html",
787 RequestContentType::None => ""
788 }
789 }
790}