diff options
| author | John Turner <jturner.usa@gmail.com> | 2026-03-04 20:53:24 -0500 |
|---|---|---|
| committer | John Turner <jturner.usa@gmail.com> | 2026-03-04 20:53:32 -0500 |
| commit | 4a16841789604614bc495c36972236749e5f35b0 (patch) | |
| tree | ff7383c17f5d265967a1db083884fec78062e53f /src/handler | |
| parent | 3c4208abd325d317c7524ba0dc3b701edfa9ebf8 (diff) | |
| download | httpd-4a16841789604614bc495c36972236749e5f35b0.tar.gz | |
roll our own http types
Diffstat (limited to 'src/handler')
| -rw-r--r-- | src/handler/staticfile.rs | 70 |
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")), + } + } +} |
