summaryrefslogtreecommitdiff
path: root/src/handler/staticfile.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/handler/staticfile.rs')
-rw-r--r--src/handler/staticfile.rs75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/handler/staticfile.rs b/src/handler/staticfile.rs
new file mode 100644
index 0000000..f208528
--- /dev/null
+++ b/src/handler/staticfile.rs
@@ -0,0 +1,75 @@
+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(match request.method() {
+ Method::Get => Body::File(file),
+ Method::Head => Body::Empty,
+ }))
+ } else {
+ Ok(Response::builder()
+ .status(Status::NotFound)
+ .headers([("content-length", "0")])
+ .body(Body::Empty))
+ }
+ }
+ Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => Ok(Response::builder()
+ .status(Status::NotFound)
+ .headers([("content-length", "0")])
+ .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")),
+ }
+ }
+}