mod base64;
mod client;
pub mod config;
mod encoding;
pub mod request;
pub mod response;
#[cfg(feature = "ws")]
pub mod websocket;
use crate::client::{Client, Scheme};
use crate::config::Config;
use crate::request::Request;
use crate::response::Response;
#[cfg(feature = "ws")]
use crate::websocket::{CloseCode, ErrorCode, Message, Websocket};
use log::{error, info, warn};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
use std::io::{Error, ErrorKind};
use std::net::{IpAddr, SocketAddr, TcpListener};
use std::sync::Arc;
use std::time::{Duration};
use std::{io, thread};
#[derive(Clone, Debug)]
pub struct WebServer;
impl WebServer {
#[cfg(feature = "service")]
pub fn new_service(config: Config, factory: fn(config: Config) -> Box<dyn Handler>) {
loop {
match WebServer::service(config.clone(), factory) {
Ok(_) => {}
Err(e) => error!("{}[{}]: {}", file!(), line!(), e),
};
warn!("服务器 2秒后重启");
thread::sleep(Duration::from_secs(2));
}
}
#[cfg(feature = "service")]
fn service(config: Config, factory: fn(config: Config) -> Box<dyn Handler>) -> io::Result<()> {
info!("==================== 网络服务 服务信息 ====================");
info!(
"日志记录: {}",
if config.is_save_log {
"开启"
} else {
"关闭"
}
);
info!(
"调试模式: {}",
if config.is_debug { "开启" } else { "关闭" }
);
info!("地 址: {}", format!("{}", config.host));
info!("端 口 号: {}", format!("{}", config.port));
info!(
"服务地址: {}",
format!(
"{}://{}{}",
if config.https { "https" } else { "http" },
config.host,
if config.port > 0 {
format!(":{}", config.port)
} else {
"".to_string()
}
)
);
info!("根 目 录: {}", format!("{}", config.root_path));
info!("访问目录: {}", format!("{}", config.public));
info!("运行目录: {}", format!("{}", config.runtime));
info!(
"SSL/TLS: {}",
format!("{}", if config.https { "开启" } else { "关闭" })
);
if config.https {
info!("证书目录KEY: {}", format!("{:?}", config.tls.key));
info!("证书目录PEM: {}", format!("{:?}", config.tls.certs));
}
let addrs = [SocketAddr::from((
IpAddr::V4(config.host.parse().unwrap()),
config.port,
))];
let listener = TcpListener::bind(&addrs[..])?;
info!("==================== 网络服务 启动成功 ====================");
let acceptor = if config.https {
let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;
if !config.tls.key.is_file() {
return Err(Error::new(
ErrorKind::Other,
format!("private.key 不存在: {:?}", config.tls.key).as_str(),
));
}
if !config.tls.certs.is_file() {
return Err(Error::new(
ErrorKind::Other,
format!("certificate.pem 不存在: {:?}", config.tls.certs).as_str(),
));
}
acceptor.set_private_key_file(config.tls.key.clone(), SslFiletype::PEM)?;
acceptor.set_certificate_file(config.tls.certs.clone(), SslFiletype::PEM)?;
Arc::new(acceptor.build())
} else {
Arc::new(SslAcceptor::mozilla_intermediate(SslMethod::tls())?.build())
};
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let config_new = config.clone();
let acceptor = acceptor.clone();
thread::spawn(move || {
if config_new.write_timeout > 0 {
stream
.set_write_timeout(Some(Duration::from_secs(
config_new.write_timeout,
)))
.unwrap_or_default();
}
if config_new.read_timeout > 0 {
stream
.set_read_timeout(Some(Duration::from_secs(
config_new.read_timeout,
)))
.unwrap_or_default();
}
let client_ip = stream.peer_addr().unwrap().ip().to_string();
let server_ip = stream.local_addr().unwrap().ip().to_string();
let scheme = match config_new.https {
true => match acceptor.accept(stream.try_clone().unwrap()) {
Ok(e) => Scheme::Https(e,client_ip.clone()),
Err(_) => return,
},
false => Scheme::Http(stream.try_clone().unwrap(),client_ip.clone()),
};
let client = Client {
config: config_new.clone(),
request: Request::default(),
response: Response::default(),
server_ip,
client_ip,
factory,
};
match client.handle_service(scheme) {
Ok(_) => {}
Err(e) => error!("{}", e),
};
});
}
Err(e) => return Err(e),
}
}
Ok(())
}
#[cfg(feature = "webpage")]
pub fn new_webpage(config: Config, factory: fn(config: Config) -> Box<dyn Handler>) {
loop {
match WebServer::webpage(config.clone(), factory) {
Ok(_) => {}
Err(e) => error!("{}[{}]: {}", file!(), line!(), e),
};
warn!("服务器 2秒后重启");
thread::sleep(Duration::from_secs(2));
}
}
#[cfg(feature = "webpage")]
fn webpage(config: Config, factory: fn(config: Config) -> Box<dyn Handler>) -> io::Result<()> {
info!("==================== 网络服务 服务信息 ====================");
info!(
"日志记录: {}",
if config.is_save_log {
"开启"
} else {
"关闭"
}
);
info!(
"调试模式: {}",
if config.is_debug { "开启" } else { "关闭" }
);
info!("地 址: {}", format!("{}", config.host));
info!("端 口 号: {}", format!("{}", config.port));
info!(
"服务地址: {}",
format!(
"{}://{}{}",
if config.https { "https" } else { "http" },
config.host,
if config.port > 0 {
format!(":{}", config.port)
} else {
"".to_string()
}
)
);
info!("根 目 录: {}", format!("{}", config.root_path));
info!("访问目录: {}", format!("{}", config.public));
info!("运行目录: {}", format!("{}", config.runtime));
info!("网页目录: {}", format!("{}", config.webpage));
info!(
"SSL/TLS: {}",
format!("{}", if config.https { "开启" } else { "关闭" })
);
if config.https {
info!("证书目录KEY: {}", format!("{:?}", config.tls.key));
info!("证书目录PEM: {}", format!("{:?}", config.tls.certs));
}
let addrs = [SocketAddr::from((
IpAddr::V4(config.host.parse().unwrap()),
config.port,
))];
let listener = TcpListener::bind(&addrs[..])?;
info!("==================== 网络服务 启动成功 ====================");
let acceptor = if config.https {
let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;
if !config.tls.key.is_file() {
return Err(Error::new(
ErrorKind::Other,
format!("private.key 不存在: {:?}", config.tls.key).as_str(),
));
}
if !config.tls.certs.is_file() {
return Err(Error::new(
ErrorKind::Other,
format!("certificate.pem 不存在: {:?}", config.tls.certs).as_str(),
));
}
acceptor.set_private_key_file(config.tls.key.clone(), SslFiletype::PEM)?;
acceptor.set_certificate_file(config.tls.certs.clone(), SslFiletype::PEM)?;
Arc::new(acceptor.build())
} else {
Arc::new(SslAcceptor::mozilla_intermediate(SslMethod::tls())?.build())
};
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let config_new = config.clone();
let acceptor = acceptor.clone();
thread::spawn(move || {
if config_new.write_timeout > 0 {
stream
.set_write_timeout(Some(Duration::from_secs(
config_new.write_timeout,
)))
.unwrap_or_default();
}
if config_new.read_timeout > 0 {
stream
.set_read_timeout(Some(Duration::from_secs(
config_new.read_timeout,
)))
.unwrap_or_default();
}
let client_ip = stream.peer_addr().unwrap().to_string();
let server_ip = stream.local_addr().unwrap().to_string();
let scheme = match config_new.https {
true => match acceptor.accept(stream.try_clone().unwrap()) {
Ok(e) => Scheme::Https(e, client_ip.clone()),
Err(_) => return,
},
false => Scheme::Http(stream.try_clone().unwrap(), client_ip.clone()),
};
let client = Client {
config: config_new.clone(),
request: Request::default(),
response: Response::default(),
factory,
server_ip,
client_ip,
};
match client.handle_webpage(scheme) {
Ok(_) => {}
Err(e) => error!("{}", e),
};
});
}
Err(e) => return Err(e),
}
}
Ok(())
}
}
pub trait Handler {
#[cfg(any(feature = "webpage", feature = "service"))]
fn on_request(&mut self, request: Request, response: Response) -> Response;
#[cfg(any(feature = "webpage", feature = "service"))]
fn on_options(&mut self, _request: Request, mut response: Response) -> Response {
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Methods", "*");
response.header("Access-Control-Allow-Headers", "*");
response.header("Access-Control-Allow-Credentials", "true");
response.header("Access-Control-Expose-Headers", "content-disposition");
response.header("Access-Control-Max-Age", "0");
response
}
#[cfg(any(feature = "service", feature = "webpage"))]
fn on_response(&mut self, request: Request, mut response: Response) -> Response {
if !response.config.origin.is_empty() {
let origin = request.header.get("origin").unwrap_or(&"".into()).clone();
if !origin.is_empty() && response.config.origin.contains(&origin.to_string().clone()) {
response.header("Access-Control-Allow-Origin", origin.as_str().unwrap_or(""));
}
} else {
response.header("Access-Control-Allow-Origin", "*");
}
response
}
#[cfg(feature = "ws")]
fn on_open(&mut self, _websocket: Websocket) -> io::Result<()> {
Ok(())
}
#[cfg(feature = "ws")]
fn on_message(&mut self, _msg: Message) -> io::Result<()> {
Ok(())
}
#[cfg(feature = "ws")]
fn on_close(&mut self, _code: CloseCode, _reason: &str) {}
#[cfg(feature = "ws")]
fn on_error(&mut self, _err: ErrorCode) {}
#[cfg(feature = "ws")]
fn on_shutdown(&mut self) {}
#[cfg(feature = "ws")]
fn on_ping(&mut self, _msg: Message) {}
#[cfg(feature = "ws")]
fn on_pong(&mut self, _msg: Message) {}
}