summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2023-12-07 14:35:48 +0100
committermetamuffin <metamuffin@disroot.org>2023-12-07 14:35:48 +0100
commit6566cbb3f25aa8b1247c259b5e546910b6044f93 (patch)
treee94dd775fc1fd90b4ea7b272d871e71118f102f6
parentab0d780062bff88d4fbcdd2c91ad5352c0d6279f (diff)
downloadgnix-6566cbb3f25aa8b1247c259b5e546910b6044f93.tar
gnix-6566cbb3f25aa8b1247c259b5e546910b6044f93.tar.bz2
gnix-6566cbb3f25aa8b1247c259b5e546910b6044f93.tar.zst
move some files around and add horrible access log
-rw-r--r--src/config.rs13
-rw-r--r--src/filters/accesslog.rs48
-rw-r--r--src/filters/auth.rs (renamed from src/auth.rs)0
-rw-r--r--src/filters/files.rs (renamed from src/files.rs)0
-rw-r--r--src/filters/mod.rs5
-rw-r--r--src/filters/proxy.rs (renamed from src/proxy.rs)0
-rw-r--r--src/main.rs31
7 files changed, 88 insertions, 9 deletions
diff --git a/src/config.rs b/src/config.rs
index b60ac8c..bc4369d 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -70,6 +70,19 @@ pub enum RouteFilter {
#[serde(flatten)]
config: FileserverConfig,
},
+ AccessLog {
+ #[serde(flatten)]
+ config: AccessLogConfig,
+ },
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct AccessLogConfig {
+ pub file: PathBuf,
+ #[serde(default)]
+ pub flush: bool,
+ #[serde(default)]
+ pub reject_on_fail: bool,
}
#[derive(Debug, Serialize, Deserialize)]
diff --git a/src/filters/accesslog.rs b/src/filters/accesslog.rs
new file mode 100644
index 0000000..ff5a8d5
--- /dev/null
+++ b/src/filters/accesslog.rs
@@ -0,0 +1,48 @@
+use crate::{config::AccessLogConfig, error::ServiceError, FilterRequest, State};
+use futures::executor::block_on;
+use log::error;
+use std::{net::SocketAddr, ops::ControlFlow};
+use tokio::{
+ fs::OpenOptions,
+ io::{AsyncWriteExt, BufWriter},
+};
+
+pub async fn access_log(
+ state: &State,
+ host: &str,
+ addr: SocketAddr,
+ config: &AccessLogConfig,
+ req: &FilterRequest,
+) -> Result<ControlFlow<()>, ServiceError> {
+ let mut g = state.access_logs.write().await;
+
+ let log = g.entry(host.to_owned()).or_insert_with(|| {
+ BufWriter::new(
+ // TODO aaahh dont block the runtime and dont panic in any case....
+ block_on(
+ OpenOptions::new()
+ .append(true)
+ .create(true)
+ .open(&config.file),
+ )
+ .unwrap(),
+ )
+ });
+
+ let method = req.method().as_str();
+ let mut res = log
+ .write_all(format!("{addr}\t{method}\t{:?}\n", req.uri()).as_bytes())
+ .await;
+
+ if config.flush && res.is_ok() {
+ res = log.flush().await;
+ }
+
+ if config.reject_on_fail {
+ res?
+ } else if let Err(e) = res {
+ error!("failed to write log: {e:?}")
+ }
+
+ Ok(ControlFlow::Continue(()))
+}
diff --git a/src/auth.rs b/src/filters/auth.rs
index 92a9ba3..92a9ba3 100644
--- a/src/auth.rs
+++ b/src/filters/auth.rs
diff --git a/src/files.rs b/src/filters/files.rs
index 733d045..733d045 100644
--- a/src/files.rs
+++ b/src/filters/files.rs
diff --git a/src/filters/mod.rs b/src/filters/mod.rs
new file mode 100644
index 0000000..fdeed51
--- /dev/null
+++ b/src/filters/mod.rs
@@ -0,0 +1,5 @@
+
+pub mod auth;
+pub mod files;
+pub mod proxy;
+pub mod accesslog; \ No newline at end of file
diff --git a/src/proxy.rs b/src/filters/proxy.rs
index 40ebf17..40ebf17 100644
--- a/src/proxy.rs
+++ b/src/filters/proxy.rs
diff --git a/src/main.rs b/src/main.rs
index 807d0ab..07f3d5c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,19 +2,16 @@
#![feature(exclusive_range_pattern)]
#![feature(slice_split_once)]
-pub mod auth;
pub mod config;
pub mod error;
-pub mod files;
+pub mod filters;
pub mod helper;
-pub mod proxy;
#[cfg(feature = "mond")]
pub mod reporting;
use crate::{
config::{Config, RouteFilter},
- files::serve_files,
- proxy::proxy_request,
+ filters::{files::serve_files, proxy::proxy_request},
};
use anyhow::{bail, Context, Result};
use bytes::Bytes;
@@ -35,7 +32,7 @@ use log::{debug, error, info, warn};
#[cfg(feature = "mond")]
use reporting::Reporting;
use std::{
- fs::File,
+ collections::HashMap,
io::BufReader,
net::SocketAddr,
ops::ControlFlow,
@@ -45,6 +42,8 @@ use std::{
sync::Arc,
};
use tokio::{
+ fs::File,
+ io::BufWriter,
net::TcpListener,
signal::ctrl_c,
sync::{RwLock, Semaphore},
@@ -53,11 +52,13 @@ use tokio_rustls::TlsAcceptor;
pub struct State {
pub config: RwLock<Arc<Config>>,
+ pub access_logs: RwLock<HashMap<String, BufWriter<File>>>,
pub l_incoming: Semaphore,
pub l_outgoing: Semaphore,
#[cfg(feature = "mond")]
pub reporting: Reporting,
}
+pub struct HostState {}
pub type FilterRequest = Request<Incoming>;
pub type FilterResponseOut = Option<Response<BoxBody<Bytes, ServiceError>>>;
@@ -89,6 +90,7 @@ async fn main() -> anyhow::Result<()> {
#[cfg(feature = "mond")]
reporting: Reporting::new(&config),
config: RwLock::new(Arc::new(config)),
+ access_logs: Default::default(),
});
if state.config.read().await.watch_config {
@@ -228,12 +230,12 @@ pub async fn serve_stream<T: Unpin + Send + 'static + hyper::rt::Read + hyper::r
}
fn load_certs(path: &Path) -> anyhow::Result<Vec<rustls::Certificate>> {
- let mut reader = BufReader::new(File::open(path).context("reading tls certs")?);
+ let mut reader = BufReader::new(std::fs::File::open(path).context("reading tls certs")?);
let certs = rustls_pemfile::certs(&mut reader).context("parsing tls certs")?;
Ok(certs.into_iter().map(rustls::Certificate).collect())
}
fn load_private_key(path: &Path) -> anyhow::Result<rustls::PrivateKey> {
- let mut reader = BufReader::new(File::open(path).context("reading tls private key")?);
+ let mut reader = BufReader::new(std::fs::File::open(path).context("reading tls private key")?);
let keys =
rustls_pemfile::pkcs8_private_keys(&mut reader).context("parsing tls private key")?;
if keys.len() != 1 {
@@ -263,6 +265,7 @@ async fn service(
#[cfg(feature = "mond")]
state.reporting.hosts.get(host).unwrap().requests_in.inc();
+ // TODO this code is horrible
let mut req = Some(req);
let mut resp = None;
for filter in &route.0 {
@@ -285,11 +288,21 @@ async fn service(
);
ControlFlow::Continue(())
}
- RouteFilter::HttpBasicAuth { config } => auth::http_basic(
+ RouteFilter::HttpBasicAuth { config } => filters::auth::http_basic(
config,
req.as_ref().ok_or(ServiceError::RequestTaken)?,
&mut resp,
)?,
+ RouteFilter::AccessLog { config } => {
+ filters::accesslog::access_log(
+ &state,
+ host,
+ addr,
+ config,
+ req.as_ref().ok_or(ServiceError::RequestTaken)?,
+ )
+ .await?
+ }
};
match cf {
ControlFlow::Continue(_) => continue,