Add virtual hosts and user configuration.
This commit is contained in:
parent
65297831c8
commit
14eb58669c
4 changed files with 168 additions and 27 deletions
93
Cargo.lock
generated
93
Cargo.lock
generated
|
@ -42,6 +42,12 @@ version = "0.8.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.7.0"
|
||||
|
@ -66,6 +72,22 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
|
@ -83,9 +105,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.119"
|
||||
version = "0.2.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
|
@ -96,6 +118,12 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.8"
|
||||
|
@ -216,12 +244,28 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.171"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9"
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "starfig"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"packeteer",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -238,6 +282,40 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
@ -265,3 +343,12 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "starfig"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
@ -8,3 +8,4 @@ edition = "2021"
|
|||
[dependencies]
|
||||
packeteer = { version = "0.2.2", features = ["gemini"] }
|
||||
native-tls = "0.2.8"
|
||||
toml = "0.7.6"
|
||||
|
|
11
config.example.toml
Normal file
11
config.example.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[starfig]
|
||||
pfx = "identity.pfx"
|
||||
bind_address = "0.0.0.0:1965"
|
||||
|
||||
[hosts]
|
||||
redirect_invalid_hosts = false
|
||||
active = [ "default" ]
|
||||
|
||||
[hosts.default]
|
||||
domain = "example.org"
|
||||
root = "/srv/gemini/content"
|
62
src/main.rs
62
src/main.rs
|
@ -9,17 +9,18 @@ use std::sync::Arc;
|
|||
use std::fs::File;
|
||||
use std::fs;
|
||||
use std::thread;
|
||||
use toml::Table;
|
||||
|
||||
fn load_page(segments: Vec<String>) -> String {
|
||||
fn load_page(segments: Vec<String>, vhost_root: String) -> String {
|
||||
let empty: Vec<String> = vec![];
|
||||
if segments == empty {
|
||||
let page = fs::read_to_string("content/index.gmi");
|
||||
let page = fs::read_to_string(format!("{}/index.gmi", vhost_root));
|
||||
match page {
|
||||
Ok(i) => i.to_string(),
|
||||
Err(_e) => "# 51 Not Found\nThe resource you were looking for couldn't be found :(\nStarfig, gemini server by threeoh6000".to_string(),
|
||||
}
|
||||
} else {
|
||||
let mut m = "content".to_string();
|
||||
let mut m = vhost_root.to_string();
|
||||
for v in segments {
|
||||
m = format!("{}/{}", m, v);
|
||||
}
|
||||
|
@ -34,12 +35,24 @@ fn load_page(segments: Vec<String>) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn serve(mut stream: TlsStream<TcpStream>) {
|
||||
fn serve(mut stream: TlsStream<TcpStream>, vhosts: Vec<String>, vhost_roots: Vec<String>, redirect: bool) {
|
||||
let mut request = Vec::new();
|
||||
let mut reader = BufReader::new(&mut stream);
|
||||
reader.read_until(b'\n', &mut request).expect("Stream failed to be read.");
|
||||
let req = construct_request(&String::from_utf8_lossy(&request).to_string());
|
||||
let file = load_page(req.url.segments);
|
||||
|
||||
let mut loc = usize::MAX;
|
||||
let mut i = 0;
|
||||
for vhost in &vhosts {
|
||||
if vhost == &req.url.domain {
|
||||
loc = i;
|
||||
} else {
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if loc != usize::MAX {
|
||||
let file = load_page(req.url.segments, vhost_roots[loc].to_string());
|
||||
let mut res = generate_response(20, &file);
|
||||
if file == "# 51 Not Found\nThe resource you were looking for couldn't be found :(\nStarfig, gemini server by threeoh6000" {
|
||||
res.code = 51;
|
||||
|
@ -56,29 +69,58 @@ fn serve(mut stream: TlsStream<TcpStream>) {
|
|||
stream.flush().unwrap();
|
||||
stream.write(res_bod.as_bytes()).unwrap();
|
||||
stream.flush().unwrap();
|
||||
stream.shutdown();
|
||||
} else {
|
||||
let mut res = generate_response(20, "");
|
||||
if redirect {
|
||||
res.code = 30;
|
||||
res.meta = format!("gemini://{}", vhosts[0].to_string());
|
||||
} else {
|
||||
res.code = 40;
|
||||
}
|
||||
|
||||
let (res_head, res_bod) = unpack_response(res);
|
||||
stream.write(res_head.as_bytes()).unwrap();
|
||||
stream.flush().unwrap();
|
||||
stream.write(res_bod.as_bytes()).unwrap();
|
||||
stream.flush().unwrap();
|
||||
}
|
||||
|
||||
let _ = stream.shutdown();
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
|
||||
let mut file = File::open("identity.pfx").unwrap();
|
||||
let configfile = fs::read_to_string("config.toml").unwrap();
|
||||
let config = configfile.parse::<Table>().unwrap();
|
||||
let mut file = File::open(config["starfig"]["pfx"].as_str().unwrap()).unwrap();
|
||||
let mut identity = vec![];
|
||||
file.read_to_end(&mut identity).unwrap();
|
||||
let identity = Identity::from_pkcs12(&identity, "").unwrap();
|
||||
|
||||
let listener = TcpListener::bind("0.0.0.0:1965").unwrap();
|
||||
let mut vhosts: Vec<String> = vec![];
|
||||
let mut vhost_roots: Vec<String> = vec![];
|
||||
|
||||
for host in config["hosts"]["active"].clone().try_into::<Vec<String>>().unwrap() {
|
||||
vhosts.push(config["hosts"][host.clone()]["domain"].as_str().unwrap().to_string());
|
||||
vhost_roots.push(config["hosts"][host.clone()]["root"].as_str().unwrap().to_string());
|
||||
}
|
||||
|
||||
let listener = TcpListener::bind(format!("{}", config["starfig"]["bind_address"].as_str().unwrap())).unwrap();
|
||||
let acceptor = TlsAcceptor::new(identity).unwrap();
|
||||
let acceptor = Arc::new(acceptor);
|
||||
for stream in listener.incoming() {
|
||||
match stream {
|
||||
Ok(stream) => {
|
||||
let vhc = vhosts.to_vec();
|
||||
let vrc = vhost_roots.to_vec();
|
||||
let redirect = config["hosts"]["redirect_invalid_hosts"].as_bool().unwrap();
|
||||
let acceptor = acceptor.clone();
|
||||
thread::spawn(move || {
|
||||
let stream = acceptor.accept(stream).unwrap();
|
||||
serve(stream);
|
||||
serve(stream, vhc, vrc, redirect);
|
||||
});
|
||||
}
|
||||
Err(e) => { /* connection failed */ }
|
||||
Err(_) => { /* connection failed */ }
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue