chore: much better readable code

This commit is contained in:
javalsai 2025-07-02 03:36:36 +02:00
parent 3c27eb55d7
commit db5247c713
Signed by: javalsai
SSH Key Fingerprint: SHA256:3G83yKhBUWVABVX/vPWH88xnK4+ptMtHkZGCRXD4Mk8
8 changed files with 152 additions and 86 deletions

62
Cargo.lock generated
View File

@ -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",

View File

@ -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"

View File

@ -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" ]

View File

@ -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 {

View File

@ -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<PathBuf>,
pub hosts: RwLock<HashMap<String, SocketAddr>>,
pub hosts: RwLock<HashMap<String, (SocketAddr, String, String)>>,
}

View File

@ -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<config::Schema>)
"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::<net::SocketAddr>() {
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::<Vec<_>>(),
)
{
match value.parse::<net::SocketAddr>() {
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<config::Schema>)
"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");
}

View File

@ -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");
};

26
src/utils.rs Normal file
View File

@ -0,0 +1,26 @@
pub mod headers {
use std::borrow::Cow;
pub trait HeadersExt<'a> {
fn has_any(&self, headers: impl IntoIterator<Item = &'_ str>) -> bool {
headers.into_iter().any(|h| self.has(h))
}
fn has_all(&self, headers: impl IntoIterator<Item = &'_ str>) -> bool {
headers.into_iter().all(|h| self.has(h))
}
fn has(&self, header: &str) -> bool;
fn get(&self, header: &str) -> Option<Cow<'a, str>>;
}
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<Cow<'a, str>> {
self.iter()
.find(|h| h.name.eq_ignore_ascii_case(header))
.map(|h| String::from_utf8_lossy(h.value))
}
}
}