It works kinda?
This commit is contained in:
16
Cargo.toml
Normal file
16
Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "gemserv"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["int 80h <int@80h.dev>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tokio = { version = "0.2", features = [ "net", "io-util", "rt-threaded" ] }
|
||||||
|
tokio-rustls = "*"
|
||||||
|
futures-util = "*"
|
||||||
|
toml = "*"
|
||||||
|
serde = "*"
|
||||||
|
serde_derive = "*"
|
||||||
|
url = "*"
|
||||||
29
src/config.rs
Normal file
29
src/config.rs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
extern crate serde_derive;
|
||||||
|
extern crate toml;
|
||||||
|
use toml::de::Error;
|
||||||
|
// use serde_derive::Deserialize;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct Config {
|
||||||
|
pub port: i32,
|
||||||
|
pub host: String,
|
||||||
|
pub server: Vec<Server>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct Server {
|
||||||
|
pub url: String,
|
||||||
|
pub dir: String,
|
||||||
|
pub key: String,
|
||||||
|
pub cert: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn new(file: &str) -> Config {
|
||||||
|
let fd = std::fs::read_to_string(file).unwrap();
|
||||||
|
let config: Config = toml::from_str(&fd).unwrap();
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
113
src/main.rs
Normal file
113
src/main.rs
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::net::ToSocketAddrs;
|
||||||
|
use std::io::{ self, BufReader };
|
||||||
|
use futures_util::future::TryFutureExt;
|
||||||
|
use tokio::prelude::*;
|
||||||
|
use tokio::runtime;
|
||||||
|
use tokio::net::TcpListener;
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
|
use tokio_rustls::rustls::{ Certificate, NoClientAuth, PrivateKey, ServerConfig };
|
||||||
|
use tokio_rustls::rustls::internal::pemfile::{ certs, pkcs8_private_keys };
|
||||||
|
use tokio_rustls::TlsAcceptor;
|
||||||
|
use tokio_rustls::server::TlsStream;
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
use url::Url;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
|
||||||
|
fn load_certs(path: &String) -> io::Result<Vec<Certificate>> {
|
||||||
|
certs(&mut BufReader::new(File::open(path)?))
|
||||||
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_keys(path: &String) -> PrivateKey {
|
||||||
|
let keyfile = File::open(path)
|
||||||
|
.expect("cannot open private key file");
|
||||||
|
let mut reader = BufReader::new(keyfile);
|
||||||
|
let key = pkcs8_private_keys(&mut reader)
|
||||||
|
.expect("file contains invalid rsa private key");
|
||||||
|
return key[0].clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_content(request: String) -> String {
|
||||||
|
|
||||||
|
let url = Url::parse(&request).unwrap();
|
||||||
|
|
||||||
|
let path = match url.path() {
|
||||||
|
"/" => String::from("index.gemini"),
|
||||||
|
path => str::replace(path, "/", ""),
|
||||||
|
};
|
||||||
|
|
||||||
|
let fd = std::fs::read_to_string(path)
|
||||||
|
.expect("Unable to read file");
|
||||||
|
|
||||||
|
fd
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_connection(mut stream: TlsStream<TcpStream>) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut buffer = [0;512];
|
||||||
|
stream.read(&mut buffer).await?;
|
||||||
|
let request = String::from_utf8_lossy(&buffer[..]).to_owned();
|
||||||
|
println!("Request: {}", request);
|
||||||
|
|
||||||
|
stream.write_all(&b"20\ttext/gemini\r\n"[..]).await?;
|
||||||
|
stream.flush().await?;
|
||||||
|
|
||||||
|
let content = get_content(request.to_string());
|
||||||
|
stream.write_all(content.as_bytes()).await?;
|
||||||
|
stream.flush().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let cfg = config::Config::new("config.toml");
|
||||||
|
|
||||||
|
let addr = format!("{}:{}", cfg.host, cfg.port);
|
||||||
|
addr.to_socket_addrs()?
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?;
|
||||||
|
|
||||||
|
let certs = load_certs(&cfg.server[0].cert)?;
|
||||||
|
let keys = load_keys(&cfg.server[0].key);
|
||||||
|
|
||||||
|
let mut runtime = runtime::Builder::new()
|
||||||
|
.threaded_scheduler()
|
||||||
|
.enable_io()
|
||||||
|
.build()?;
|
||||||
|
let handle = runtime.handle().clone();
|
||||||
|
let mut config = ServerConfig::new(NoClientAuth::new());
|
||||||
|
config.set_single_cert(certs, keys)
|
||||||
|
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
|
||||||
|
let acceptor = TlsAcceptor::from(Arc::new(config));
|
||||||
|
|
||||||
|
println!("Serving");
|
||||||
|
|
||||||
|
let fut = async {
|
||||||
|
let mut listener = TcpListener::bind(&addr).await?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let (stream, peer_addr) = listener.accept().await?;
|
||||||
|
let acceptor = acceptor.clone();
|
||||||
|
|
||||||
|
let fut = async move {
|
||||||
|
let stream = acceptor.accept(stream).await?;
|
||||||
|
handle_connection(stream).await;
|
||||||
|
println!("Hello: {}", peer_addr);
|
||||||
|
|
||||||
|
Ok(()) as io::Result<()>
|
||||||
|
};
|
||||||
|
|
||||||
|
handle.spawn(fut.unwrap_or_else(|err| eprintln!("{:?}", err)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
runtime.block_on(fut)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user