agate

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

commit 76bbfafee56bc19f90ad617f986bfbb2fd6b73ef
parent 59c921c5d5ce212bd4494057cd74e543749902b0
Author: Matt Brubeck <mbrubeck@limpet.net>
Date:   Sat, 20 Jun 2020 10:02:36 -0700

Minor cleanup

Diffstat:
Msrc/main.rs | 65+++++++++++++++++++++++++++++++++--------------------------------
1 file changed, 33 insertions(+), 32 deletions(-)

diff --git a/src/main.rs b/src/main.rs @@ -8,26 +8,17 @@ use { }, async_tls::TlsAcceptor, once_cell::sync::Lazy, - std::{error::Error, ffi::OsStr, marker::Unpin, str, sync::Arc}, + std::{error::Error, ffi::OsStr, fs::File, io::BufReader, marker::Unpin, sync::Arc}, url::Url, }; -pub type Result<T=()> = std::result::Result<T, Box<dyn Error + Send + Sync>>; - -struct Args { - sock_addr: String, - content_dir: String, - cert_file: String, - key_file: String, -} - fn main() -> Result { block_on(async { let listener = TcpListener::bind(&ARGS.sock_addr).await?; let mut incoming = listener.incoming(); while let Some(Ok(stream)) = incoming.next().await { spawn(async { - if let Err(e) = connection(stream).await { + if let Err(e) = handle_request(stream).await { eprintln!("Error: {:?}", e); } }); @@ -36,6 +27,18 @@ fn main() -> Result { }) } +type Result<T=()> = std::result::Result<T, Box<dyn Error + Send + Sync>>; + +static ARGS: Lazy<Args> = + Lazy::new(|| args().expect("usage: agate <addr:port> <dir> <cert> <key>")); + +struct Args { + sock_addr: String, + content_dir: String, + cert_file: String, + key_file: String, +} + fn args() -> Option<Args> { let mut args = std::env::args().skip(1); Some(Args { @@ -46,12 +49,27 @@ fn args() -> Option<Args> { }) } -static ARGS: Lazy<Args> = - Lazy::new(|| args().expect("usage: agate <addr:port> <dir> <cert> <key>")); +/// Handle a single client session (request + response). +async fn handle_request(stream: TcpStream) -> Result { + // Perform handshake. + static TLS: Lazy<TlsAcceptor> = Lazy::new(|| acceptor().unwrap()); + let mut stream = TLS.accept(stream).await?; + + match parse_request(&mut stream).await { + Ok(url) => { + eprintln!("Got request for {:?}", url); + send_response(&url, &mut stream).await + } + Err(e) => { + stream.write_all(b"59 Invalid request.\r\n").await?; + Err(e) + } + } +} +/// TLS configuration. fn acceptor() -> Result<TlsAcceptor> { use rustls::{ServerConfig, NoClientAuth, internal::pemfile::{certs, pkcs8_private_keys}}; - use std::{io::BufReader, fs::File}; let cert_file = File::open(&ARGS.cert_file)?; let certs = certs(&mut BufReader::new(cert_file)).or(Err("bad cert"))?; @@ -64,23 +82,6 @@ fn acceptor() -> Result<TlsAcceptor> { Ok(TlsAcceptor::from(Arc::new(config))) } -/// Handle a single client session (request + response). -async fn connection(stream: TcpStream) -> Result { - static ACCEPTOR: Lazy<TlsAcceptor> = Lazy::new(|| acceptor().unwrap()); - - let mut stream = ACCEPTOR.accept(stream).await?; - match parse_request(&mut stream).await { - Ok(url) => { - eprintln!("Got request for {:?}", url); - send_response(&url, &mut stream).await - } - Err(e) => { - stream.write_all(b"59 Invalid request.\r\n").await?; - Err(e) - } - } -} - /// Return the URL requested by the client. async fn parse_request<R: Read + Unpin>(mut stream: R) -> Result<Url> { // Because requests are limited to 1024 bytes (plus 2 bytes for CRLF), we @@ -101,7 +102,7 @@ async fn parse_request<R: Read + Unpin>(mut stream: R) -> Result<Url> { } buf = &mut request[len..]; } - let request = str::from_utf8(&request[..len - 2])?; + let request = std::str::from_utf8(&request[..len - 2])?; // Handle scheme-relative URLs. let url = if request.starts_with("//") {