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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
|
@ -66,6 +72,22 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
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]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
|
@ -83,9 +105,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.119"
|
version = "0.2.147"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
|
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
|
@ -96,6 +118,12 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "native-tls"
|
name = "native-tls"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
|
@ -216,12 +244,28 @@ dependencies = [
|
||||||
"libc",
|
"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]]
|
[[package]]
|
||||||
name = "starfig"
|
name = "starfig"
|
||||||
version = "0.1.2"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"native-tls",
|
"native-tls",
|
||||||
"packeteer",
|
"packeteer",
|
||||||
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -238,6 +282,40 @@ dependencies = [
|
||||||
"winapi",
|
"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]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
@ -265,3 +343,12 @@ name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
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]
|
[package]
|
||||||
name = "starfig"
|
name = "starfig"
|
||||||
version = "0.1.2"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
@ -8,3 +8,4 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
packeteer = { version = "0.2.2", features = ["gemini"] }
|
packeteer = { version = "0.2.2", features = ["gemini"] }
|
||||||
native-tls = "0.2.8"
|
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"
|
88
src/main.rs
88
src/main.rs
|
@ -9,17 +9,18 @@ use std::sync::Arc;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::thread;
|
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![];
|
let empty: Vec<String> = vec![];
|
||||||
if segments == empty {
|
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 {
|
match page {
|
||||||
Ok(i) => i.to_string(),
|
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(),
|
Err(_e) => "# 51 Not Found\nThe resource you were looking for couldn't be found :(\nStarfig, gemini server by threeoh6000".to_string(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut m = "content".to_string();
|
let mut m = vhost_root.to_string();
|
||||||
for v in segments {
|
for v in segments {
|
||||||
m = format!("{}/{}", m, v);
|
m = format!("{}/{}", m, v);
|
||||||
}
|
}
|
||||||
|
@ -34,51 +35,92 @@ 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 request = Vec::new();
|
||||||
let mut reader = BufReader::new(&mut stream);
|
let mut reader = BufReader::new(&mut stream);
|
||||||
reader.read_until(b'\n', &mut request).expect("Stream failed to be read.");
|
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 req = construct_request(&String::from_utf8_lossy(&request).to_string());
|
||||||
let file = load_page(req.url.segments);
|
|
||||||
let mut res = generate_response(20, &file);
|
let mut loc = usize::MAX;
|
||||||
if file == "# 51 Not Found\nThe resource you were looking for couldn't be found :(\nStarfig, gemini server by threeoh6000" {
|
let mut i = 0;
|
||||||
res.code = 51;
|
for vhost in &vhosts {
|
||||||
|
if vhost == &req.url.domain {
|
||||||
|
loc = i;
|
||||||
|
} else {
|
||||||
|
i = i + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if res.code == 20 {
|
|
||||||
res.meta = "text/gemini".to_string();
|
if loc != usize::MAX {
|
||||||
} else if res.code == 51 {
|
let file = load_page(req.url.segments, vhost_roots[loc].to_string());
|
||||||
res.meta = "Not Found".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;
|
||||||
|
}
|
||||||
|
if res.code == 20 {
|
||||||
|
res.meta = "text/gemini".to_string();
|
||||||
|
} else if res.code == 51 {
|
||||||
|
res.meta = "Not Found".to_string();
|
||||||
|
} else {
|
||||||
|
res.meta = "Err".to_string();
|
||||||
|
}
|
||||||
|
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();
|
||||||
} else {
|
} else {
|
||||||
res.meta = "Err".to_string();
|
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 (res_head, res_bod) = unpack_response(res);
|
|
||||||
stream.write(res_head.as_bytes()).unwrap();
|
let _ = stream.shutdown();
|
||||||
stream.flush().unwrap();
|
|
||||||
stream.write(res_bod.as_bytes()).unwrap();
|
|
||||||
stream.flush().unwrap();
|
|
||||||
stream.shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
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![];
|
let mut identity = vec![];
|
||||||
file.read_to_end(&mut identity).unwrap();
|
file.read_to_end(&mut identity).unwrap();
|
||||||
let identity = Identity::from_pkcs12(&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 = TlsAcceptor::new(identity).unwrap();
|
||||||
let acceptor = Arc::new(acceptor);
|
let acceptor = Arc::new(acceptor);
|
||||||
for stream in listener.incoming() {
|
for stream in listener.incoming() {
|
||||||
match stream {
|
match stream {
|
||||||
Ok(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();
|
let acceptor = acceptor.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let stream = acceptor.accept(stream).unwrap();
|
let stream = acceptor.accept(stream).unwrap();
|
||||||
serve(stream);
|
serve(stream, vhc, vrc, redirect);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Err(e) => { /* connection failed */ }
|
Err(_) => { /* connection failed */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue