The following Rust code:
use tokio::net::TcpListener;
use tokio_rustls::TlsAcceptor;
use rustls_pemfile::{certs, rsa_private_keys};
use std::fs::File;
use std::io::{self, BufReader};
use std::path::Path;
use tokio::io::{split, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio_rustls::rustls::{Certificate, PrivateKey};
lazy_static::lazy_static! {
static ref RESPONSE_200:&'static str = concat!(
"HTTP/1.1 200 OK\r\n" ,
"Content-Length: 11\r\n" ,
"Connection: closed\r\n\r\n",
"Are you OK?",
);
}
pub fn load_certs(path: &Path) -> io::Result<Vec<Certificate>> {
certs(&mut BufReader::new(File::open(path)?))
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))
.map(|mut certs| certs.drain(..).map(Certificate).collect())
}
pub fn load_keys(path: &Path) -> io::Result<Vec<PrivateKey>> {
rsa_private_keys(&mut BufReader::new(File::open(path)?))
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key"))
.map(|mut keys| keys.drain(..).map(PrivateKey).collect())
}
pub fn init(cert_path: &str, key_path: &str) -> io::Result<TlsAcceptor> {
let certs = load_certs(Path::new(cert_path))?;
let mut keys = load_keys(Path::new(key_path))?;
let server_conf = tokio_rustls::rustls::ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()
.with_single_cert(certs, keys.remove(0))
.map_err(|_err| io::Error::new(io::ErrorKind::InvalidInput, "TLS cert loading error"))?;
Ok(TlsAcceptor::from(std::sync::Arc::new(server_conf)))
}
pub async fn handle<IO>(stream: IO) -> io::Result<()>
where
IO: AsyncRead + AsyncWrite + Unpin + AsyncWriteExt,
{
let (mut local_reader, mut local_writer) = split(stream);
let mut head = [0u8; 2048];
let n = local_reader.read(&mut head[..]).await?;
if n == 2048 {
return Err(io::Error::new(
io::ErrorKind::Other,
"Receive a unexpected big size of header!!",
));
}
let head_str = std::str::from_utf8(&head[..n])
.map_err(|x| io::Error::new(io::ErrorKind::Interrupted, x))?;
println!("\r\nReceived request from client: \r\n{}\r\n", head_str);
// 回复200OK
local_writer.write_all(RESPONSE_200.as_bytes()).await?;
local_writer.shutdown().await?;
Ok(()) as io::Result<()>
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "192.168.30.26:18443";
let listener = TcpListener::bind(addr).await.unwrap();
println!("Server running on port 18443");
let acceptor = init("server.crt", "server.key")?;
loop {
match listener.accept().await {
Ok((stream, _peer_addr)) => {
let acceptor = acceptor.clone();
match acceptor.accept(stream).await {
Ok(stream) => {
tokio::spawn(async move {
if let Err(_err) = handle(stream).await {
eprintln!("TLS Handler err: {:?}", _err);
}
});
}
Err(_err) => {
eprintln!("Tls err: {:?}", _err);
}
}
}
Err(_err) => {
eprintln!("Tcp err: {:?}", _err);
}
}
}
}
[package]
name = "https_server"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio = {version = "1", features = ["full"]}
tokio-rustls = { version = "0.23.4", features = ["dangerous_configuration"] }
tokio-native-tls = "0.3"
rustls-pemfile = "0.2"
lazy_static = "1.4.0"