1#[cfg(feature = "client")]
2pub mod client;
3mod client_response;
4pub mod config;
5pub mod request;
6pub mod response;
7pub mod stream;
8pub mod url;
9pub mod websocket;
10
11use crate::config::Config;
12use crate::request::Request;
13use crate::response::Response;
14use crate::stream::Scheme;
15use crate::websocket::{CloseCode, ErrorCode, Message, Websocket};
16use fs::read;
17use log::{error, info, warn};
18
19use rustls_pemfile::certs;
20
21use flate2::read::GzDecoder;
22use flate2::write::GzEncoder;
23use flate2::Compression;
24use json::{object, JsonValue};
25use rustls::{ServerConfig, ServerConnection, StreamOwned};
26use std::fmt::Debug;
27use std::io::{BufReader, Error, Read, Write};
28use std::net::TcpListener;
29use std::path::PathBuf;
30use std::sync::{Arc, Mutex};
31use std::time::Duration;
32use std::{fs, io, thread};
33
34#[derive(Clone, Debug)]
36pub struct WebServer;
37
38impl WebServer {
39 pub fn new_service(config: Config, factory: fn(out: Websocket) -> Box<dyn Handler>) {
41 loop {
42 match WebServer::service(config.clone(), factory) {
43 Ok(()) => {}
44 Err(e) => error!("服务器错误: {}[{}]: {}", file!(), line!(), e),
45 }
46 warn!("服务器 1秒后重启");
47 thread::sleep(Duration::from_secs(1));
48 }
49 }
50 fn service(config: Config, factory: fn(out: Websocket) -> Box<dyn Handler>) -> io::Result<()> {
51 info!("==================== 网络服务 服务信息 ====================");
52 info!("日志记录: {}", if config.log { "开启" } else { "关闭" });
53 info!("调试模式: {}", if config.debug { "开启" } else { "关闭" });
54 info!("监听地址: {}", config.host);
55 info!(
56 "服务地址: {}://{}",
57 if config.https { "https" } else { "http" },
58 config.host
59 );
60 info!("根 目 录: {}", config.root_path.to_str().unwrap());
61 info!("访问目录: {}", config.public);
62 info!("运行目录: {}", config.runtime);
63 info!("SSL/TLS: {}", if config.https { "开启" } else { "关闭" });
64
65 if config.https {
66 info!("证书目录KEY: {:?}", config.tls.key);
67 info!("证书目录PEM: {:?}", config.tls.certs);
68 }
69
70 let listener = TcpListener::bind(config.host.clone())?;
71 info!("==================== 网络服务 启动成功 ====================");
72
73 let acceptor = Self::ssl(config.clone())?;
74 for stream in listener.incoming() {
75 match stream {
76 Ok(stream) => {
77 let config_new = config.clone();
78 let acceptor_new = acceptor.clone();
79 thread::spawn(move || -> io::Result<()> {
80 stream.set_nonblocking(false)?;
81 stream
82 .set_read_timeout(Some(Duration::from_secs(config_new.read_timeout)))
83 .unwrap_or_default();
84 stream
85 .set_write_timeout(Some(Duration::from_secs(config_new.write_timeout)))
86 .unwrap_or_default();
87
88 let scheme = if config_new.https {
89 let conn = match ServerConnection::new(acceptor_new.unwrap()) {
90 Ok(e) => e,
91 Err(e) => {
92 return Err(Error::other(e.to_string()));
93 }
94 };
95 Scheme::Https(Arc::new(Mutex::new(StreamOwned::new(conn, stream))))
96 } else {
97 Scheme::Http(Arc::new(Mutex::new(stream)))
98 };
99
100 let mut request =
101 Request::new(config_new.clone(), Arc::new(Mutex::new(scheme.clone())));
102 let response = match request.handle() {
103 Ok(()) => Response::new(&request.clone(), factory),
104 Err(e) => {
105 return Err(Error::other(e.body.as_str()));
107 }
108 };
109 match response.handle() {
110 Ok(()) => {}
111 Err(e) => {
112 return Err(Error::other(e));
114 }
115 };
116
117 match request.save_log() {
118 Ok(()) => {}
119 Err(_) => error!("日志记录错误"),
120 }
121 Ok(())
122 });
123 }
124 Err(e) => return Err(e),
125 }
126 }
127 Ok(())
128 }
129 fn ssl(config: Config) -> io::Result<Option<Arc<ServerConfig>>> {
130 if config.https {
131 if !config.tls.key.is_file() {
132 return Err(Error::other(
133 format!("private.key 不存在: {:?}", config.tls.key.clone()).as_str(),
134 ));
135 }
136 if !config.tls.certs.is_file() {
137 return Err(Error::other(
138 format!("certificate.pem 不存在: {:?}", config.tls.certs).as_str(),
139 ));
140 }
141 let t = read(config.tls.key)?;
142 let mut reader = BufReader::new(t.as_slice());
143 let key = rustls_pemfile::private_key(&mut reader).unwrap().unwrap();
144 let t = read(config.tls.certs)?;
145 let mut reader = BufReader::new(t.as_slice());
146 let certs = certs(&mut reader)
147 .collect::<Result<Vec<_>, _>>()?
148 .as_slice()
149 .to_owned();
150
151 let config = match ServerConfig::builder()
152 .with_no_client_auth()
154 .with_single_cert(certs, key)
156 {
157 Ok(e) => e,
158 Err(e) => return Err(Error::other(e)),
159 };
160
161 Ok(Some(Arc::new(config)))
162 } else {
177 Ok(None)
178 }
179 }
180}
181
182pub trait HandlerClone {
183 fn clone_box(&self) -> Box<dyn Handler>;
184}
185
186impl<T> HandlerClone for T
188where
189 T: 'static + Handler + Clone,
190{
191 fn clone_box(&self) -> Box<dyn Handler> {
192 Box::new(self.clone())
193 }
194}
195
196impl Clone for Box<dyn Handler> {
198 fn clone(&self) -> Box<dyn Handler> {
199 self.clone_box()
200 }
201}
202pub trait Handler: Send + Sync + HandlerClone + Debug {
203 fn on_request(&mut self, _request: Request, _response: &mut Response);
205 fn on_options(&mut self, response: &mut Response) {
207 response.allow_origins = vec![];
208 response.allow_methods = vec!["GET", "POST", "PUT", "DELETE", "OPTIONS"];
209 response.allow_headers = vec!["Authorization", "X-Forwarded-For", "X-Real-IP"];
210 response.header("Access-Control-Expose-Headers", "Content-Disposition");
211 response.header("Access-Control-Max-Age", 86400.to_string().as_str());
212 }
213 fn on_response(&mut self, response: &mut Response) {
215 if !response.headers.has_key("Access-Control-Allow-Origin") {
216 response.header("Access-Control-Allow-Origin", "*");
217 }
218 if !response.headers.has_key("Access-Control-Allow-Credentials") {
220 response.header("Access-Control-Allow-Credentials", "true");
221 }
222 }
227
228 fn on_frame(&mut self) -> Result<(), HttpError> {
229 Ok(())
230 }
231 fn on_open(&mut self) -> Result<(), HttpError> {
233 Ok(())
234 }
235 fn on_message(&mut self, _msg: Message) -> Result<(), HttpError> {
237 Ok(())
238 }
239 fn on_close(&mut self, _code: CloseCode, _reason: &str) {}
241 fn on_error(&mut self, _err: ErrorCode) {}
243 fn on_shutdown(&mut self) {}
245}
246
247#[derive(Clone, Debug)]
248pub enum Connection {
249 KeepAlive,
251 Close,
253 Other(String),
254}
255impl Connection {
256 pub fn from(value: &str) -> Self {
257 match value.to_lowercase().as_str() {
258 "keep-alive" => Self::KeepAlive,
259 "close" => Self::Close,
260 _ => Self::Other(value.to_string()),
261 }
262 }
263 pub fn str(&self) -> &str {
264 match self {
265 Connection::KeepAlive => "keep-alive",
266 Connection::Close => "close",
267 Connection::Other(name) => name,
268 }
269 }
270}
271#[derive(Clone, Debug)]
272pub enum Upgrade {
273 Websocket,
274 Http,
275 H2c,
276 Other(String),
277}
278impl Upgrade {
279 pub fn from(name: &str) -> Self {
280 match name.to_lowercase().as_str() {
281 "websocket" => Upgrade::Websocket,
282 "http" => Upgrade::Http,
283 "h2c" => Upgrade::H2c,
284 _ => Upgrade::Other(name.to_lowercase().as_str().to_string()),
285 }
286 }
287 pub fn str(&self) -> &str {
288 match self {
289 Upgrade::Websocket => "websocket",
290 Upgrade::Http => "http",
291 Upgrade::H2c => "h2c",
292 Upgrade::Other(name) => name,
293 }
294 }
295}
296
297#[derive(Clone, Debug, Default)]
299pub struct Uri {
300 pub uri: String,
302 pub url: String,
304 pub query: String,
306 pub fragment: String,
308 pub path: String,
310 pub path_segments: Vec<String>,
312}
313impl Uri {
314 pub fn from(url: &str) -> Self {
315 let mut decoded_url = br_crypto::encoding::urlencoding_decode(url);
316 let fragment = match decoded_url.rfind('#') {
317 None => String::new(),
318 Some(index) => decoded_url.drain(index..).collect::<String>(),
319 };
320
321 let query = match decoded_url.rfind('?') {
322 None => String::new(),
323 Some(index) => decoded_url
324 .drain(index..)
325 .collect::<String>()
326 .trim_start_matches("?")
327 .to_string(),
328 };
329
330 let path_segments = decoded_url
331 .split('/')
332 .map(|x| x.to_string())
333 .filter(|x| !x.is_empty())
334 .collect::<Vec<String>>();
335 Self {
336 uri: decoded_url.clone(),
337 url: url.to_string(),
338 query,
339 fragment,
340 path: decoded_url.clone(),
341 path_segments,
342 }
343 }
344 #[must_use]
346 pub fn get_query_params(&self) -> JsonValue {
347 let text = self.query.split('&').collect::<Vec<&str>>();
348 let mut params = object! {};
349 for item in text {
350 if let Some(index) = item.find('=') {
351 let key = item[..index].to_string();
352 let value = item[index + 1..].to_string();
353 let _ = params.insert(key.as_str(), value);
354 }
355 }
356 params
357 }
358 #[must_use]
359 pub fn to_json(&self) -> JsonValue {
360 object! {
361 url: self.url.clone(),
362 query: self.query.clone(),
363 fragment: self.fragment.clone(),
364 path: self.path.clone(),
365 path_segments: self.path_segments.clone()
366 }
367 }
368}
369
370#[derive(Clone, Debug)]
372pub enum Method {
373 POST,
375 GET,
377 HEAD,
379 PUT,
381 DELETE,
383 OPTIONS,
385 PATCH,
386 TRACE,
387 VIEW,
388 CONNECT,
389 PROPFIND,
390 PRI,
392 Other(String),
394}
395
396impl Method {
397 #[must_use]
398 pub fn from(name: &str) -> Self {
399 match name.to_lowercase().as_str() {
400 "post" => Self::POST,
401 "get" => Self::GET,
402 "head" => Self::HEAD,
403 "put" => Self::PUT,
404 "delete" => Self::DELETE,
405 "options" => Self::OPTIONS,
406 "patch" => Self::PATCH,
407 "trace" => Self::TRACE,
408 "view" => Self::VIEW,
409 "propfind" => Self::PROPFIND,
410 "connect" => Self::CONNECT,
411 "pri" => Self::PRI,
412 _ => Self::Other(name.to_string()),
413 }
414 }
415 pub fn str(&self) -> &str {
416 match self {
417 Self::POST => "POST",
418 Self::GET => "GET",
419 Self::HEAD => "HEAD",
420 Self::PUT => "PUT",
421 Self::DELETE => "DELETE",
422 Self::OPTIONS => "OPTIONS",
423 Self::PATCH => "PATCH",
424 Self::TRACE => "TRACE",
425 Self::VIEW => "VIEW",
426 Self::PROPFIND => "PROPFIND",
427 Self::PRI => "PRI",
428 Self::CONNECT => "CONNECT",
429 Method::Other(e) => e.to_lowercase().leak(),
430 }
431 }
432}
433
434#[derive(Debug, Clone)]
435pub struct HttpError {
436 pub code: u16,
437 pub body: String,
438}
439
440impl HttpError {
441 #[must_use]
443 pub fn new(code: u16, body: &str) -> Self {
444 Self {
445 code,
446 body: body.to_string(),
447 }
448 }
449}
450#[derive(Debug, Clone)]
452pub enum ContentType {
453 FormData,
454 FormUrlencoded,
455 Json,
456 Xml,
457 Javascript,
458 Text,
459 Html,
460 Stream,
461 Other(String),
462}
463impl ContentType {
464 #[must_use]
465 pub fn from(name: &str) -> Self {
466 match name {
467 "multipart/form-data" => Self::FormData,
468 "application/x-www-form-urlencoded" => Self::FormUrlencoded,
469 "application/json" => Self::Json,
470 "application/xml" | "text/xml" => Self::Xml,
471 "application/javascript" => Self::Javascript,
472 "application/octet-stream" => Self::Stream,
473 "text/html" => Self::Html,
474 "text/plain" => Self::Text,
475 _ => Self::Other(name.to_string()),
476 }
477 }
478 #[must_use]
479 pub fn str(&self) -> &str {
480 match self {
481 ContentType::FormData => "multipart/form-data",
482 ContentType::FormUrlencoded => "application/x-www-form-urlencoded",
483 ContentType::Json => "application/json",
484 ContentType::Xml => "application/xml",
485 ContentType::Javascript => "application/javascript",
486 ContentType::Text => "text/plain",
487 ContentType::Html => "text/html",
488 ContentType::Other(name) => name.as_str(),
489 ContentType::Stream => "application/octet-stream",
490 }
491 }
492}
493
494pub(crate) fn parse_content_type_header_value(
503 value: &str,
504) -> (String, std::collections::HashMap<String, String>) {
505 let mut it = value.split(';');
506 let mime = it.next().unwrap_or("").trim().to_lowercase();
507
508 let mut params = std::collections::HashMap::<String, String>::new();
509 for raw in it {
510 let raw = raw.trim();
511 if raw.is_empty() {
512 continue;
513 }
514 if let Some((k, v)) = raw.split_once('=') {
515 let key = k.trim().to_lowercase();
516 let mut val = v.trim();
517 if val.len() >= 2 && val.starts_with('"') && val.ends_with('"') {
518 val = &val[1..val.len() - 1];
519 }
520 params.insert(key, val.to_string());
521 } else {
522 params.insert(raw.to_lowercase(), String::new());
524 }
525 }
526
527 (mime, params)
528}
529#[derive(Clone, Debug)]
531pub enum Authorization {
532 Basic(String, String),
533 Bearer(String),
534 Digest(JsonValue),
535 Other(String),
536}
537impl Authorization {
538 #[must_use]
539 pub fn from(data: &str) -> Self {
540 let authorization = data.split_whitespace().collect::<Vec<&str>>();
541 let mode = authorization[0].to_lowercase();
542 match mode.as_str() {
543 "basic" => {
544 let text = br_crypto::base64::decode(&authorization[1].to_string().clone());
545 let text: Vec<&str> = text.split(':').collect();
546 Self::Basic(text[0].to_string(), text[1].to_string())
547 }
548 "bearer" => Self::Bearer(authorization[1].to_string()),
549 "digest" => {
550 let text = authorization[1..].concat().clone();
551 let text = text.split(',').collect::<Vec<&str>>();
552 let mut params = object! {};
553 for item in &text {
554 let Some(index) = item.find('=') else {
555 continue;
556 };
557 let key = item[..index].to_string();
558 let value = item[index + 2..item.len() - 1].to_string();
559 let _ = params.insert(key.as_str(), value);
560 }
561 Self::Digest(params)
562 }
563 _ => Self::Other(data.to_string()),
564 }
565 }
566 pub fn str(&self) -> JsonValue {
567 match self {
568 Self::Basic(key, value) => {
569 let mut data = object! {};
570 data[key.as_str()] = value.clone().into();
571 data
572 }
573 Self::Bearer(e) => e.clone().into(),
574 Self::Digest(e) => e.clone(),
575 Self::Other(name) => name.clone().into(),
576 }
577 }
578}
579#[derive(Clone, Debug)]
581pub enum Content {
582 FormUrlencoded(JsonValue),
583 FormData(JsonValue),
584 Json(JsonValue),
585 Text(JsonValue),
586 Xml(JsonValue),
587 None,
588}
589impl Content {}
590#[derive(Clone, Debug)]
591pub enum FormData {
592 File(String, PathBuf),
593 Field(JsonValue),
594}
595
596#[derive(Clone, Debug)]
598pub enum Language {
599 ZhCN,
600 ZhHans,
601 En,
602 Other(String),
603}
604impl Language {
605 #[must_use]
606 pub fn from(name: &str) -> Self {
607 let binding = name.split(',').collect::<Vec<&str>>()[0]
608 .trim()
609 .to_lowercase();
610 let name = binding.as_str();
611 match name {
612 "zh-cn" => Self::ZhCN,
613 "zh-hans" => Self::ZhHans,
614 "en" => Self::En,
615 _ => Self::Other(name.to_string()),
616 }
617 }
618 #[must_use]
619 pub fn str(&self) -> &str {
620 match self {
621 Language::ZhCN => "zh-CN",
622 Language::ZhHans => "zh-Hans",
623 Language::En => "en",
624 Language::Other(e) => e.as_str(),
625 }
626 }
627}
628
629#[derive(Clone, Debug)]
631pub enum Encoding {
632 Gzip,
633 Deflate,
634 Br,
635 Bzip2,
636 None,
637}
638impl Encoding {
639 #[must_use]
640 pub fn from(s: &str) -> Encoding {
641 match s.to_lowercase().as_str() {
642 x if x.contains("gzip") => Encoding::Gzip,
643 x if x.contains("deflate") => Encoding::Deflate,
644 x if x.contains("br") => Encoding::Br,
645 x if x.contains("bzip2") => Encoding::Bzip2,
646 _ => Encoding::None,
647 }
648 }
649 #[must_use]
650 pub fn str(&self) -> &str {
651 match self {
652 Encoding::Gzip => "gzip",
653 Encoding::Deflate => "deflate",
654 Encoding::Br => "br",
655 Encoding::Bzip2 => "bzip2",
656 Encoding::None => "",
657 }
658 }
659 pub fn compress(&mut self, data: &[u8]) -> Result<Vec<u8>, String> {
661 match self {
662 Encoding::Gzip => {
663 let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
664 match encoder.write_all(data) {
665 Ok(()) => {}
666 Err(e) => {
667 return Err(format!("Failed to compress file {}", e));
668 }
669 };
670 match encoder.finish() {
671 Ok(e) => Ok(e),
672 Err(e) => Err(format!("Failed to compress file {}", e)),
673 }
674 }
675 _ => Ok(data.to_vec()),
676 }
677 }
678 pub fn decompress(&mut self, data: &[u8]) -> Result<Vec<u8>, String> {
680 match self {
681 Encoding::Gzip => {
682 let mut d = GzDecoder::new(data);
683 let mut s = String::new();
684 match d.read_to_string(&mut s) {
685 Ok(_) => {}
686 Err(e) => {
687 return Err(format!("Failed to decompress file {}", e));
688 }
689 };
690 Ok(s.as_bytes().to_vec())
691 }
692 Encoding::Br => {
693 let mut decompressed = Vec::new();
694 let mut reader = brotli::Decompressor::new(data, 4096);
695 reader
696 .read_to_end(&mut decompressed)
697 .map_err(|e| format!("brotli decompress error: {e}"))?;
698 Ok(decompressed)
699 }
700 _ => Ok(data.to_vec()),
701 }
702 }
703}
704
705#[derive(Clone, Debug)]
707pub enum Protocol {
708 HTTP1_0,
709 HTTP1_1,
710 HTTP2,
711 HTTP3,
712 Other(String),
713}
714
715impl Protocol {
716 pub fn from(name: &str) -> Self {
717 match name.to_lowercase().as_str() {
718 "http/1.0" => Protocol::HTTP1_0,
719 "http/1.1" => Protocol::HTTP1_1,
720 "http/2.0" | "http/2" => Protocol::HTTP2,
721 "http/3.0" | "http/3" => Protocol::HTTP3,
722 _ => Protocol::Other(name.to_lowercase()),
723 }
724 }
725 pub fn str(&self) -> &str {
726 match self {
727 Protocol::HTTP1_0 => "HTTP/1.0",
728 Protocol::HTTP1_1 => "HTTP/1.1",
729 Protocol::HTTP2 => "HTTP/2.0",
730 Protocol::HTTP3 => "HTTP/3.0",
731 Protocol::Other(protocol) => protocol.as_str(),
732 }
733 }
734}
735#[derive(Clone, Debug)]
737pub struct Status {
738 pub code: u16,
739 reason: String,
740}
741impl Status {
742 pub fn set_code(&mut self, code: u16) {
743 self.code = code;
744 self.reason = match code {
745 100 => "Continue", 101 => "Switching Protocols", 102 => "Processing",
748 103 => "Early Hints", 200 => "OK", 201 => "Created", 202 => "Accepted", 204 => "No Content", 206 => "Partial Content", 301 => "Moved Permanently", 302 => "Found", 303 => "See Other", 304 => "Not Modified", 307 => "Temporary Redirect", 308 => "Permanent Redirect", 400 => "Bad Request", 401 => "Unauthorized", 403 => "Forbidden",
764 404 => "Not Found", 405 => "Method Not Allowed", 411 => "Length Required", 413 => "Payload Too Large", 414 => "URI Too Long", 416 => "Range Not Satisfiable",
770 429 => "Too Many Requests", 431 => "Request Header Fields Too Large", 500 => "Internal Server Error", 501 => "Not Implemented", 502 => "Bad Gateway", 503 => "Service Unavailable", 504 => "Gateway Time-out", 505 => "HTTP Version Not Supported", _ => "",
780 }
781 .to_string();
782 }
783 pub fn from(code: u16, reason: &str) -> Self {
784 Status {
785 code,
786 reason: reason.to_string(),
787 }
788 }
789}
790impl Default for Status {
791 fn default() -> Self {
792 Self {
793 code: 200,
794 reason: "OK".to_string(),
795 }
796 }
797}
798
799#[derive(Debug)]
800pub enum TransferEncoding {
801 Chunked,
802 Other(String),
803}
804impl TransferEncoding {
805 pub fn from(name: &str) -> TransferEncoding {
806 match name.to_lowercase().as_str() {
807 "chunked" => TransferEncoding::Chunked,
808 _ => TransferEncoding::Other(name.to_string()),
809 }
810 }
811}
812
813pub fn split_boundary(mut data: Vec<u8>, boundary: &str) -> Result<Vec<Vec<u8>>, String> {
814 let boundary = format!("--{boundary}");
815 let boundary_bytes = boundary.as_bytes();
816 let mut list = vec![];
817 loop {
818 if let Some(n) = data
819 .windows(boundary_bytes.len())
820 .position(|x| x == boundary_bytes)
821 {
822 let drain_end = n + boundary_bytes.len();
824 if drain_end > data.len() {
825 return Err("格式错误: boundary 超出数据范围".to_string());
826 }
827 data.drain(..drain_end);
828 if data.is_empty() || data.starts_with(b"--\r\n") || data.starts_with(b"--") {
829 break;
830 }
831 if data.starts_with(b"\r\n") {
833 data.drain(..2);
834 }
835 } else {
836 return Err("格式错误: 未找到 boundary".to_string());
837 }
838 if let Some(n) = data
839 .windows(boundary_bytes.len())
840 .position(|x| x == boundary_bytes)
841 {
842 if n > 0 {
843 let content_end = if n >= 2 && data[n - 2..n] == *b"\r\n" {
845 n - 2
846 } else {
847 n
848 };
849 list.push(data[..content_end].to_vec());
850 }
851 data.drain(..n);
852 } else {
853 return Err("格式错误: 未找到结束 boundary".to_string());
854 }
855 }
856 Ok(list)
857}