From db5247c713750e35a629335c56b039b0a0608c20 Mon Sep 17 00:00:00 2001 From: javalsai Date: Wed, 2 Jul 2025 03:36:36 +0200 Subject: [PATCH] chore: much better readable code --- Cargo.lock | 62 ++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + config.default.toml | 2 +- src/args/mod.rs | 2 +- src/config/mod.rs | 5 +-- src/ipc/mod.rs | 82 ++++++++++++++++++++------------------------- src/main.rs | 58 ++++++++++++-------------------- src/utils.rs | 26 ++++++++++++++ 8 files changed, 152 insertions(+), 86 deletions(-) create mode 100644 src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 73aaa23..d8a52ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + [[package]] name = "bitflags" version = "2.9.1" @@ -172,6 +178,17 @@ version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", + "serde", +] + [[package]] name = "memchr" version = "2.7.5" @@ -196,6 +213,29 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -214,6 +254,21 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +dependencies = [ + "bitflags", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "serde" version = "1.0.219" @@ -249,6 +304,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + [[package]] name = "strsim" version = "0.11.1" @@ -315,6 +376,7 @@ dependencies = [ "clap", "ctrlc", "httparse", + "parking_lot", "serde", "shlex", "toml", diff --git a/Cargo.toml b/Cargo.toml index 71430f8..36071db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ anstyle = "1" clap = { version = "4", features = ["derive", "string"] } ctrlc = "3" httparse = "1" +parking_lot = { version = "0", features = ["arc_lock", "serde"] } serde = { version = "1", features = ["derive"] } shlex = "1" toml = "0" diff --git a/config.default.toml b/config.default.toml index 9174558..9783715 100644 --- a/config.default.toml +++ b/config.default.toml @@ -1,4 +1,4 @@ listen_at = "127.0.0.1:8080" [hosts] -"git.tuxcord.net" = "127.0.0.1:3000" +"git.tuxcord.net" = [ "127.0.0.1:3000", "i_like_gitea", "_csrf" ] diff --git a/src/args/mod.rs b/src/args/mod.rs index 663a5e7..f98a56d 100644 --- a/src/args/mod.rs +++ b/src/args/mod.rs @@ -19,7 +19,7 @@ pub struct Args { pub enum Commands { /// Connects to the selected IPC #[cfg(feature = "ipc")] - Ipc, + Ipc, // TODO: add -c flag for an automatic command } fn get_clap_styles() -> clap::builder::Styles { diff --git a/src/config/mod.rs b/src/config/mod.rs index fb1bf5b..c400ae2 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,5 +1,6 @@ -use std::{collections::HashMap, net::SocketAddr, path::PathBuf, sync::RwLock}; +use std::{collections::HashMap, net::SocketAddr, path::PathBuf}; +use parking_lot::RwLock; use serde::Deserialize; #[derive(Deserialize, Debug)] @@ -7,5 +8,5 @@ pub struct Schema { pub listen_at: SocketAddr, #[cfg(feature = "ipc")] pub ipc: Option, - pub hosts: RwLock>, + pub hosts: RwLock>, } diff --git a/src/ipc/mod.rs b/src/ipc/mod.rs index 29bdd19..b72b566 100644 --- a/src/ipc/mod.rs +++ b/src/ipc/mod.rs @@ -1,13 +1,15 @@ -use core::net; +use core::{net, str}; use std::{ fs, io::{self, BufRead, BufReader, Write, stdout}, os::unix::net::{UnixListener, UnixStream}, process, - sync::{Arc, RwLockWriteGuard}, + sync::Arc, thread::{self, JoinHandle}, }; +use parking_lot::RwLockWriteGuard; + use crate::config; pub fn start_client(config: config::Schema) { @@ -79,41 +81,38 @@ pub fn handle_daemon_client(mut stream: UnixStream, config: Arc) "list" => { _ = writeln!(stream, "aquiring read lock"); let rlock = config.hosts.read(); - match rlock { - Ok(lock) => { - _ = writeln!(stream, "{lock:#?}"); - } - Err(err) => { - _ = writeln!(stream, "err with read lock: {err:?}"); - } - }; + _ = writeln!(stream, "{rlock:#?}"); } "create" => { if let [name, value] = args { - match value.parse::() { - Ok(addr) => { - _ = writeln!(stream, "aquiring write lock"); - let wlock = config.hosts.write(); - match wlock { - Ok(mut lock) => { - lock.insert(name.to_string(), addr); - let lock = RwLockWriteGuard::downgrade(lock); - _ = writeln!(stream, "{lock:#?}"); - } - Err(err) => { - _ = writeln!( - stream, - "err with write lock: {err:?}" - ); - } - }; - } - Err(err) => { - _ = writeln!( - stream, - "err: parsing value as socket addres {err:?}" - ); - } + if let Ok([value, id, csrf]) = + <_ as TryInto<[&str; 3]>>::try_into( + value.split(',').take(3).collect::>(), + ) + { + match value.parse::() { + Ok(addr) => { + _ = writeln!(stream, "aquiring write lock"); + let mut wlock = config.hosts.write(); + wlock.insert( + name.to_string(), + (addr, id.to_string(), csrf.to_string()), + ); + let rlock = RwLockWriteGuard::downgrade(wlock); + _ = writeln!(stream, "{rlock:#?}"); + } + Err(err) => { + _ = writeln!( + stream, + "err: parsing value as socket addres {err:?}" + ); + } + }; + } else { + _ = writeln!( + stream, + "err: value wasn't 3 comma separated values" + ); }; } else { _ = writeln!( @@ -125,17 +124,10 @@ pub fn handle_daemon_client(mut stream: UnixStream, config: Arc) "delete" => { if let [name] = args { _ = writeln!(stream, "aquiring write lock"); - let wlock = config.hosts.write(); - match wlock { - Ok(mut lock) => { - lock.remove(name); - let lock = RwLockWriteGuard::downgrade(lock); - _ = writeln!(stream, "{lock:#?}"); - } - Err(err) => { - _ = writeln!(stream, "err with write lock: {err:?}"); - } - }; + let mut wlock = config.hosts.write(); + wlock.remove(name); + let lock = RwLockWriteGuard::downgrade(wlock); + _ = writeln!(stream, "{lock:#?}"); } else { _ = writeln!(stream, "invalid arg count, expected a name"); } diff --git a/src/main.rs b/src/main.rs index 5f9dd85..3373f60 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,10 @@ //! # Tuxcord Reverse Proxy Header Authenthication -#![feature(rwlock_downgrade, try_blocks)] +#![feature( + rwlock_downgrade, + try_blocks, + iterator_try_collect, + anonymous_lifetime_in_impl_trait +)] use std::{ fs::File, @@ -11,10 +16,13 @@ use std::{ use clap::Parser; +use crate::utils::headers::HeadersExt; + pub mod args; pub mod config; #[cfg(feature = "ipc")] pub mod ipc; +pub mod utils; use args::Args; @@ -78,54 +86,30 @@ fn handle_client(client: &mut TcpStream, config: &config::Schema) -> Result<(), let mut header_buf = [0u8; 1024 * 8]; let mut read_pos = 0usize; - let pos = loop { + let mut headers; + let (pos, req) = loop { + headers = [httparse::EMPTY_HEADER; 16]; + let mut req = httparse::Request::new(&mut headers); + let Ok(n) = client.read(&mut header_buf[read_pos..]) else { return Err("error reading stream"); }; read_pos += n; - let pos = header_buf - .windows(b"\r\n\r\n".len()) - .position(|w| w == b"\r\n\r\n"); - if let Some(pos) = pos { - break pos; - }; + if let Ok(httparse::Status::Complete(n)) = req.parse(&header_buf[0..read_pos]) { + break (n - b"\r\n\r\n".len(), req); + } }; - let mut headers = [httparse::EMPTY_HEADER; 16]; - let mut req = httparse::Request::new(&mut headers); - let Ok(httparse::Status::Complete(_)) = - httparse::Request::parse(&mut req, &header_buf[0..(pos + b"\r\n\r\n".len())]) - else { - return Err("parsing request was not complete"); - }; + let theres_body = req.headers.has_any(["conten-length", "transfer-encoding"]); - let theres_body = req - .headers - .iter() - .any(|header| header.name.to_lowercase() == "content-length") - || req - .headers - .iter() - .any(|header| header.name.to_lowercase() == "transfer-encoding"); - - let Some(header) = req - .headers - .iter() - .find(|header| header.name.to_lowercase() == "host") - else { + let Some(host_header) = req.headers.get("host") else { return Err("failed to find \"host\" header"); }; - let Ok(host_header) = String::from_utf8(header.value.to_vec()) else { - return Err("\"host\" header is not valid UTF-8"); - }; - // Now find that header and pas everything - let Ok(read_hosts) = config.hosts.read() else { - return Err("poisoned RwLock"); - }; - let Some(addr) = read_hosts.get(&host_header) else { + let read_hosts = config.hosts.read(); + let Some((addr, _, _)) = read_hosts.get(host_header.as_ref()) else { return Err("host not in hashmap"); }; diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..ce0a1ed --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,26 @@ +pub mod headers { + use std::borrow::Cow; + + pub trait HeadersExt<'a> { + fn has_any(&self, headers: impl IntoIterator) -> bool { + headers.into_iter().any(|h| self.has(h)) + } + fn has_all(&self, headers: impl IntoIterator) -> bool { + headers.into_iter().all(|h| self.has(h)) + } + fn has(&self, header: &str) -> bool; + fn get(&self, header: &str) -> Option>; + } + + impl<'a> HeadersExt<'a> for &mut [httparse::Header<'a>] { + fn has(&self, header: &str) -> bool { + self.iter().any(|h| h.name.eq_ignore_ascii_case(header)) + } + + fn get(&self, header: &str) -> Option> { + self.iter() + .find(|h| h.name.eq_ignore_ascii_case(header)) + .map(|h| String::from_utf8_lossy(h.value)) + } + } +}