chore: much better readable code

This commit is contained in:
2025-07-02 03:36:36 +02:00
parent 3c27eb55d7
commit db5247c713
8 changed files with 152 additions and 86 deletions

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))
}
}
}