1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
use std::{ffi::OsString, os::unix::ffi::OsStringExt, path::PathBuf, time};
use mlua::{FromLua, Value};
use tokio::{
fs::{self, File},
io,
};
use crate::{
Handle, handlers,
request::Request,
response::{self, Response},
};
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("io error: {0}")]
Io(#[from] io::Error),
#[error("http error: {0}")]
Http(#[from] http::Error),
}
#[derive(Debug, Clone)]
pub struct StaticFile {
path: PathBuf,
mime: String,
}
impl<T> Handle<T> for StaticFile {
async fn handle(&self, request: Request<T>) -> Result<Response, handlers::Error> {
if let http::Method::GET | http::Method::HEAD = request.inner().method().clone() {
if !fs::try_exists(&self.path).await.map_err(Error::Io)? {
return Ok(Response::new(
http::Response::builder()
.status(http::StatusCode::NOT_FOUND)
.body(response::Body::Empty)
.map_err(Error::Http)?,
));
}
let file = File::open(&self.path).await.map_err(Error::Io)?;
let metadata = file.metadata().await.map_err(Error::Io)?;
let now = time::SystemTime::now();
let date = httpdate::fmt_http_date(now);
let response = http::Response::builder()
.status(http::StatusCode::OK)
.header("CONTENT-LENGTH", metadata.len())
.header("CONTENT-TYPE", &self.mime)
.header("DATE", date);
match request.inner().method().clone() {
http::Method::GET => Ok(Response::new(
response
.body(response::Body::File(file))
.map_err(Error::Http)?,
)),
http::Method::HEAD => Ok(Response::new(
response.body(response::Body::Empty).map_err(Error::Http)?,
)),
_ => unreachable!(),
}
} else {
Err(handlers::Error::Unsupported)
}
}
}
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")),
}
}
}
|