From 16c1d0c4aac9094830fc16c6975c0eb999c41f19 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Thu, 27 Jul 2023 18:00:23 +0200 Subject: [PATCH] WIP --- Cargo.lock | 100 +++++++++++++++++++++++++++++++++++++++--- Cargo.toml | 4 +- src/main.rs | 1 + src/origin/git.rs | 2 +- src/service/gemini.rs | 72 +++++++++++++++++++++++++++--- src/util.rs | 2 +- 6 files changed, 166 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b4f3867..9e66c8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -111,6 +111,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "arrayvec" version = "0.7.2" @@ -158,6 +164,18 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813" +[[package]] +name = "bitvec" +version = "0.19.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -458,9 +476,11 @@ name = "domani" version = "0.1.0" dependencies = [ "acme2", + "bytes", "clap", "env_logger", "futures", + "gemini", "gix", "handlebars", "hex", @@ -660,6 +680,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + [[package]] name = "futures" version = "0.3.28" @@ -749,6 +775,18 @@ dependencies = [ "slab", ] +[[package]] +name = "gemini" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12a820f5a9ac6f433b34944dc8d17b759d5009275c8fe12f73b873153dbcd4e0" +dependencies = [ + "nom 6.1.2", + "paste", + "thiserror", + "url", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -828,7 +866,7 @@ dependencies = [ "btoi", "gix-date", "itoa", - "nom", + "nom 7.1.3", "thiserror", ] @@ -891,7 +929,7 @@ dependencies = [ "gix-sec", "log", "memchr", - "nom", + "nom 7.1.3", "once_cell", "smallvec", "thiserror", @@ -1100,7 +1138,7 @@ dependencies = [ "gix-validate", "hex", "itoa", - "nom", + "nom 7.1.3", "smallvec", "thiserror", ] @@ -1195,7 +1233,7 @@ dependencies = [ "gix-hash", "gix-transport", "maybe-async", - "nom", + "nom 7.1.3", "thiserror", ] @@ -1226,7 +1264,7 @@ dependencies = [ "gix-tempfile", "gix-validate", "memmap2", - "nom", + "nom 7.1.3", "thiserror", ] @@ -1767,6 +1805,19 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec 0.5.2", + "bitflags 1.3.2", + "cfg-if", + "ryu", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.142" @@ -1954,6 +2005,19 @@ dependencies = [ "smallvec", ] +[[package]] +name = "nom" +version = "6.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +dependencies = [ + "bitvec", + "funty", + "lexical-core", + "memchr", + "version_check", +] + [[package]] name = "nom" version = "7.1.3" @@ -2081,6 +2145,12 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "pem" version = "2.0.1" @@ -2249,6 +2319,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" + [[package]] name = "radix_trie" version = "0.2.1" @@ -2805,6 +2881,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempdir" version = "0.3.7" @@ -3121,7 +3203,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "794a32261a1f5eb6a4462c81b59cec87b5c27d5deea7dd1ac8fc781c41d226db" dependencies = [ - "arrayvec", + "arrayvec 0.7.2", ] [[package]] @@ -3508,3 +3590,9 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] + +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/Cargo.toml b/Cargo.toml index 937cf7e..7fcf078 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ mime_guess = "2.0.4" hyper = { version = "0.14.26", features = [ "server", "stream" ]} http = "0.2.9" serde_urlencoded = "0.7.1" -tokio-util = "0.7.8" +tokio-util = { version = "0.7.8", features = [ "io" ]} acme2 = "0.5.1" openssl = "0.10.52" rustls = "0.21.1" @@ -45,6 +45,8 @@ serde_yaml = "0.9.22" rand = "0.8.5" reqwest = "0.11.18" hyper-reverse-proxy = "0.5.1" +gemini = "0.0.5" +bytes = "1.4.0" [patch.crates-io] tokio-rustls = { git = "https://code.betamike.com/micropelago/tokio-rustls.git", branch = "start-handshake-into-inner" } diff --git a/src/main.rs b/src/main.rs index 3b950d5..88fbf0c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -151,6 +151,7 @@ async fn main() { let _ = domani::service::gemini::Service::new( &mut task_stack, + domain_manager.clone(), sync::Arc::new(domain_gemini_store), config.service, ); diff --git a/src/origin/git.rs b/src/origin/git.rs index 3d00758..6535be4 100644 --- a/src/origin/git.rs +++ b/src/origin/git.rs @@ -332,7 +332,7 @@ impl super::Store for FSStore { // TODO this is very not ideal, the whole file is first read totally into memory, and then // that is cloned. - let data = file_object.data.clone(); + let data = bytes::Bytes::copy_from_slice(file_object.data.as_slice()); Ok(Box::pin(stream::once(async move { Ok(data) }))) } } diff --git a/src/service/gemini.rs b/src/service/gemini.rs index 0f24a74..51915d8 100644 --- a/src/service/gemini.rs +++ b/src/service/gemini.rs @@ -4,12 +4,13 @@ mod proxy; pub use config::*; use crate::error::unexpected::{self, Mappable}; -use crate::{domain, service, task_stack}; +use crate::{domain, service, task_stack, util}; use std::sync; use tokio_util::sync::CancellationToken; pub struct Service { + domain_manager: sync::Arc, cert_resolver: sync::Arc, config: service::Config, } @@ -26,10 +27,12 @@ enum HandleConnError { impl Service { pub fn new( task_stack: &mut task_stack::TaskStack, + domain_manager: sync::Arc, cert_resolver: sync::Arc, config: service::Config, ) -> sync::Arc { let service = sync::Arc::new(Service { + domain_manager, cert_resolver, config, }); @@ -37,6 +40,64 @@ impl Service { service } + async fn respond_conn( + &self, + w: W, + code: &str, + meta: &str, + body: Option, + ) -> unexpected::Result<()> + where + W: tokio::io::AsyncWrite + Unpin, + { + use tokio::io::{copy, AsyncWriteExt, BufWriter}; + let mut w = BufWriter::new(w); + + w.write_all(code.as_bytes()).await.or_unexpected()?; + w.write_all(" ".as_bytes()).await.or_unexpected()?; + w.write_all(meta.as_bytes()).await.or_unexpected()?; + w.write_all("\r\n".as_bytes()).await.or_unexpected()?; + + if let Some(body) = body { + let mut body = tokio_util::io::StreamReader::new(body); + copy(&mut body, &mut w).await.or_unexpected()?; + } + + w.flush().await.or_unexpected()?; + + Ok(()) + } + + async fn serve_conn(&self, domain: &domain::Name, conn: IO) -> Result<(), HandleConnError> + where + IO: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, + { + use tokio::io::*; + + let (r, w) = split(conn); + let mut r = BufReader::new(r); + + let mut req = String::with_capacity(64); + r.read_line(&mut req) + .await + .map_err(|e| HandleConnError::ClientError(format!("failed to read request: {e}")))?; + + let req = gemini::request::parse::request(req.as_bytes()) + .map(|(_, req)| req) + .map_err(|e| HandleConnError::ClientError(format!("failed to parse request: {e}")))? + .into_gemini_request() + .map_err(|e| HandleConnError::ClientError(format!("failed to parse request: {e}")))?; + + let f = match self.domain_manager.get_file(domain, req.path()) { + Ok(f) => f, + Err(domain::manager::GetFileError::DomainNotFound) => panic!("TODO"), + Err(domain::manager::GetFileError::FileNotFound) => panic!("TODO"), + Err(domain::manager::GetFileError::Unexpected(e)) => return Err(e.into()), + }; + + Ok(self.respond_conn(w, "20", "TODO", Some(f)).await?) + } + async fn proxy_conn( &self, proxied_domain: &ConfigProxiedDomain, @@ -59,7 +120,7 @@ impl Service { async fn handle_conn( &self, conn: tokio::net::TcpStream, - _tls_config: sync::Arc, + tls_config: sync::Arc, ) -> Result<(), HandleConnError> { let teed_conn = { let (r, w) = tokio::io::split(conn); @@ -92,9 +153,8 @@ impl Service { return Ok(()); } - return Err(HandleConnError::ClientError(format!( - "unknown domain {domain}" - ))); + let conn = start.into_stream(tls_config).await.or_unexpected()?; + self.serve_conn(&domain, conn).await } Err(err) => { return Err(unexpected::Error::from( @@ -113,7 +173,7 @@ async fn listen( let tls_config = sync::Arc::new( rustls::server::ServerConfig::builder() .with_safe_defaults() - .with_no_client_auth() // TODO maybe this isn't right? + .with_no_client_auth() .with_cert_resolver(service.cert_resolver.clone()), ); diff --git a/src/util.rs b/src/util.rs index c29a995..e8674ac 100644 --- a/src/util.rs +++ b/src/util.rs @@ -10,6 +10,6 @@ pub fn open_file(path: &path::Path) -> io::Result> { } } -pub type BoxByteStream = futures::stream::BoxStream<'static, io::Result>>; +pub type BoxByteStream = futures::stream::BoxStream<'static, io::Result>; pub type BoxFuture<'a, O> = pin::Pin + Send + 'a>>;