aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2023-11-14 11:54:01 +0100
committermetamuffin <metamuffin@disroot.org>2023-11-14 11:54:01 +0100
commit3b1afad1d1a697e82c003e146ef2b7d5742e5210 (patch)
tree3a9e02470b4f78c4c34c0573c788da301a9e544e /src/main.rs
parent4a7bd84594fb8d159a0a2af02818f283eab3e716 (diff)
downloadgnix-3b1afad1d1a697e82c003e146ef2b7d5742e5210.tar
gnix-3b1afad1d1a697e82c003e146ef2b7d5742e5210.tar.bz2
gnix-3b1afad1d1a697e82c003e146ef2b7d5742e5210.tar.zst
refactor architecture and start on http basic auth
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs69
1 files changed, 56 insertions, 13 deletions
diff --git a/src/main.rs b/src/main.rs
index 99374eb..059bdf0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,8 @@
#![feature(try_trait_v2)]
#![feature(exclusive_range_pattern)]
+#![feature(slice_split_once)]
+pub mod auth;
pub mod config;
pub mod error;
pub mod files;
@@ -10,11 +12,12 @@ pub mod proxy;
pub mod reporting;
use crate::{
- config::{Config, HostConfig},
+ config::{Config, RouteFilter},
files::serve_files,
proxy::proxy_request,
};
use anyhow::{anyhow, bail, Context, Result};
+use bytes::Bytes;
use error::ServiceError;
use futures::future::try_join_all;
use helper::TokioIo;
@@ -30,7 +33,10 @@ use hyper::{
use log::{debug, error, info, warn};
#[cfg(feature = "mond")]
use reporting::Reporting;
-use std::{fs::File, io::BufReader, net::SocketAddr, path::Path, process::exit, sync::Arc};
+use std::{
+ fs::File, io::BufReader, net::SocketAddr, ops::ControlFlow, path::Path, process::exit,
+ sync::Arc,
+};
use tokio::{net::TcpListener, signal::ctrl_c, sync::Semaphore};
use tokio_rustls::TlsAcceptor;
@@ -42,6 +48,10 @@ pub struct State {
pub reporting: Reporting,
}
+pub type FilterRequest = Request<Incoming>;
+pub type FilterResponseOut = Option<Response<BoxBody<Bytes, ServiceError>>>;
+pub type FilterResponse = Option<Response<BoxBody<Bytes, ServiceError>>>;
+
#[tokio::main]
async fn main() -> anyhow::Result<()> {
env_logger::init_from_env("LOG");
@@ -96,12 +106,13 @@ async fn serve_http(state: Arc<State>) -> Result<()> {
let listen_futs: Result<Vec<()>> = try_join_all(http_config.bind.iter().map(|e| async {
let l = TcpListener::bind(e.clone()).await?;
+ info!("HTTP listener bound to {}", l.local_addr().unwrap());
loop {
let (stream, addr) = l.accept().await.context("accepting connection")?;
debug!("connection from {addr}");
let stream = TokioIo(stream);
- let config = state.clone();
- tokio::spawn(async move { serve_stream(config, stream, addr).await });
+ let state = state.clone();
+ tokio::spawn(async move { serve_stream(state, stream, addr).await });
}
}))
.await;
@@ -131,9 +142,9 @@ async fn serve_https(state: Arc<State>) -> Result<()> {
Arc::new(cfg)
};
let tls_acceptor = Arc::new(TlsAcceptor::from(tls_config));
-
let listen_futs: Result<Vec<()>> = try_join_all(https_config.bind.iter().map(|e| async {
let l = TcpListener::bind(e.clone()).await?;
+ info!("HTTPS listener bound to {}", l.local_addr().unwrap());
loop {
let (stream, addr) = l.accept().await.context("accepting connection")?;
let state = state.clone();
@@ -148,8 +159,6 @@ async fn serve_https(state: Arc<State>) -> Result<()> {
}
}))
.await;
-
- info!("serving https");
listen_futs?;
Ok(())
}
@@ -170,11 +179,14 @@ pub async fn serve_stream<T: Unpin + Send + 'static + hyper::rt::Read + hyper::r
Ok(r) => Ok(r),
Err(ServiceError::Hyper(e)) => Err(e),
Err(error) => Ok({
- let mut resp =
- Response::new(format!("gnix encountered an issue: {error}"));
+ let mut resp = Response::new(format!(
+ "Sorry, we were unable to process your request: {error}"
+ ));
*resp.status_mut() = StatusCode::BAD_REQUEST;
resp.headers_mut()
.insert(CONTENT_TYPE, HeaderValue::from_static("text/plain"));
+ resp.headers_mut()
+ .insert(SERVER, HeaderValue::from_static("gnix"));
resp
}
.map(|b| b.map_err(|e| match e {}).boxed())),
@@ -226,10 +238,41 @@ async fn service(
#[cfg(feature = "mond")]
state.reporting.hosts.get(host).unwrap().requests_in.inc();
- let mut resp = match route {
- HostConfig::Backend { backend } => proxy_request(&state, req, addr, backend).await,
- HostConfig::Files { files } => serve_files(req, files).await,
- }?;
+ let mut req = Some(req);
+ let mut resp = None;
+ for filter in &route.0 {
+ let cf = match filter {
+ RouteFilter::Proxy { backend } => {
+ resp = Some(
+ proxy_request(
+ &state,
+ req.take().ok_or(ServiceError::RequestTaken)?,
+ addr,
+ backend,
+ )
+ .await?,
+ );
+ ControlFlow::Continue(())
+ }
+ RouteFilter::Files { config } => {
+ resp = Some(
+ serve_files(req.as_ref().ok_or(ServiceError::RequestTaken)?, config).await?,
+ );
+ ControlFlow::Continue(())
+ }
+ RouteFilter::HttpBasicAuth { config } => auth::http_basic(
+ config,
+ req.as_ref().ok_or(ServiceError::RequestTaken)?,
+ &mut resp,
+ )?,
+ };
+ match cf {
+ ControlFlow::Continue(_) => continue,
+ ControlFlow::Break(_) => break,
+ }
+ }
+
+ let mut resp = resp.ok_or(ServiceError::NoResponse)?;
let server_header = resp.headers().get(SERVER).cloned();
resp.headers_mut().insert(