agate

Simple gemini server for static files
git clone https://github.com/mbrubeck/agate.git
Log | Files | Refs | README

commit dd4be5b9f6f56902f244638dfe41c4810dc9b9f7
parent 4e7d09204fd9a8e4ea0ea0f8ebc244bcbd780c89
Author: Matt Brubeck <mbrubeck@limpet.net>
Date:   Sat, 16 Jan 2021 10:16:52 -0800

Take port as a separate command-line argument

Diffstat:
MREADME.md | 4+++-
Msrc/main.rs | 26++++++++++++++++++++------
2 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/README.md b/README.md @@ -33,7 +33,9 @@ openssl req -x509 -newkey rsa:4096 -keyout key.rsa -out cert.pem \ agate --content path/to/content/ \ --key key.rsa \ --cert cert.pem \ - --addr [::]:1965 \ + --addr :: \ + --addr 0.0.0.0 \ + --port 1965 \ --hostname example.com \ --lang en-US ``` diff --git a/src/main.rs b/src/main.rs @@ -11,6 +11,7 @@ use { ffi::OsStr, fs::File, io::BufReader, + net::{IpAddr, SocketAddr}, path::Path, sync::Arc, }, @@ -28,8 +29,11 @@ fn main() -> Result { env_logger::Builder::new().parse_filters("info").init(); } Runtime::new()?.block_on(async { - let listener = TcpListener::bind(&ARGS.sock_addr).await?; - log::info!("Listening on {}...", ARGS.sock_addr); + let port = ARGS.port; + let sock_addrs: Vec<_> = ARGS.addrs.iter().map(|addr| SocketAddr::new(*addr, port)).collect(); + + let listener = TcpListener::bind(&sock_addrs[..]).await?; + log::info!("Listening on {:?}...", sock_addrs); loop { let (stream, _) = listener.accept().await?; tokio::spawn(async { @@ -51,7 +55,8 @@ static ARGS: Lazy<Args> = Lazy::new(|| { }); struct Args { - sock_addr: String, + addrs: Vec<IpAddr>, + port: u16, content_dir: String, cert_file: String, key_file: String, @@ -67,7 +72,8 @@ fn args() -> Result<Args> { opts.optopt("", "content", "Root of the content directory (default ./content)", "DIR"); opts.optopt("", "cert", "TLS certificate PEM file (default ./cert.pem)", "FILE"); opts.optopt("", "key", "PKCS8 private key file (default ./key.rsa)", "FILE"); - opts.optopt("", "addr", "Address to listen on (default 0.0.0.0:1965)", "IP:PORT"); + opts.optmulti("", "addr", "Address to listen on (default 0.0.0.0 and [::])", "IP"); + opts.optopt("", "port", "Port to listen on (default 1965)", "PORT"); opts.optopt("", "hostname", "Domain name of this Gemini server (optional)", "NAME"); opts.optopt("", "lang", "RFC 4646 Language code(s) for text/gemini documents", "LANG"); opts.optflag("s", "silent", "Disable logging output"); @@ -83,8 +89,16 @@ fn args() -> Result<Args> { Some(s) => Some(Host::parse(&s)?), None => None, }; + let mut addrs = vec![]; + for i in matches.opt_strs("addr") { + addrs.push(i.parse()?); + } + if addrs.is_empty() { + addrs = vec![ "::".parse().unwrap(), "0.0.0.0".parse().unwrap()]; + } Ok(Args { - sock_addr: matches.opt_get_default("addr", "0.0.0.0:1965".into())?, + addrs, + port: matches.opt_get_default("port", 1965)?, content_dir: check_path(matches.opt_get_default("content", "content".into())?)?, cert_file: check_path(matches.opt_get_default("cert", "cert.pem".into())?)?, key_file: check_path(matches.opt_get_default("key", "key.rsa".into())?)?, @@ -166,7 +180,7 @@ async fn parse_request(stream: &mut TlsStream<TcpStream>) -> std::result::Result } } if let Some(port) = url.port() { - if !ARGS.sock_addr.ends_with(&format!(":{}", port)) { + if port != ARGS.port { return Err((53, "proxy request refused")); } }