summaryrefslogtreecommitdiff
path: root/src/handler
diff options
context:
space:
mode:
authorJohn Turner <jturner.usa@gmail.com>2026-03-04 20:53:24 -0500
committerJohn Turner <jturner.usa@gmail.com>2026-03-04 20:53:32 -0500
commit4a16841789604614bc495c36972236749e5f35b0 (patch)
treeff7383c17f5d265967a1db083884fec78062e53f /src/handler
parent3c4208abd325d317c7524ba0dc3b701edfa9ebf8 (diff)
downloadhttpd-4a16841789604614bc495c36972236749e5f35b0.tar.gz
roll our own http types
Diffstat (limited to 'src/handler')
-rw-r--r--src/handler/staticfile.rs70
1 files changed, 70 insertions, 0 deletions
diff --git a/src/handler/staticfile.rs b/src/handler/staticfile.rs
new file mode 100644
index 0000000..871f414
--- /dev/null
+++ b/src/handler/staticfile.rs
@@ -0,0 +1,70 @@
+use crate::{
+ handler::{self, Handle},
+ request::{Method, Request},
+ response::{Body, Response, Status},
+};
+
+use std::{ffi::OsString, os::unix::ffi::OsStringExt, path::PathBuf};
+
+use mlua::{FromLua, Value};
+
+use tokio::{
+ fs::File,
+ io::{self},
+};
+
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+ #[error("io error: {0}")]
+ Io(#[from] io::Error),
+}
+
+#[derive(Debug, Clone)]
+pub struct StaticFile {
+ path: PathBuf,
+ mime: String,
+}
+
+impl Handle for StaticFile {
+ async fn handle(self, request: Request) -> Result<Response, handler::Error> {
+ match request.method() {
+ Method::Get | Method::Head => match File::open(&self.path).await {
+ Ok(file) => {
+ let metadata = file.metadata().await.map_err(Error::Io)?;
+
+ if metadata.is_file() {
+ Ok(Response::builder()
+ .status(Status::Ok)
+ .headers([
+ ("content-length", format!("{}", metadata.len())),
+ ("content-type", self.mime),
+ ])
+ .body(Body::File(file)))
+ } else {
+ Ok(Response::builder()
+ .status(Status::NotFound)
+ .body(Body::Empty))
+ }
+ }
+ Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => Ok(Response::builder()
+ .status(Status::NotFound)
+ .body(Body::Empty)),
+ Err(e) => Err(Error::Io(e))?,
+ },
+ }
+ }
+}
+
+impl FromLua for StaticFile {
+ fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
+ match value {
+ Value::Table(table) => Ok(Self {
+ path: PathBuf::from(OsString::from_vec(
+ table.get::<mlua::String>("path")?.as_bytes().to_vec(),
+ )),
+ mime: table.get::<String>("mime")?,
+ }),
+ _ => Err(mlua::Error::runtime("expected table")),
+ }
+ }
+}