changeset 37:4347956773fb

Enable caching of fileserver requests
author Lewin Bormann <lbo@spheniscida.de>
date Sat, 16 Jul 2022 13:20:20 -0700
parents 0c5f8caf6736
children 305224ae5a33
files src/cacheresponder.rs src/main.rs
diffstat 2 files changed, 96 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cacheresponder.rs	Sat Jul 16 13:20:20 2022 -0700
@@ -0,0 +1,84 @@
+use log::info;
+
+use std::convert::Into;
+
+use rocket::data::Data;
+use rocket::http::Header;
+use rocket::http::Method;
+use rocket::request::Request;
+use rocket::response::Responder;
+use rocket::route::Handler;
+use rocket::route::Outcome;
+use rocket::route::Route;
+
+#[derive(Clone, Debug)]
+pub struct CacheControl(String);
+
+impl CacheControl {
+    pub fn new<S: AsRef<str>>(policy: S) -> CacheControl {
+        CacheControl(policy.as_ref().to_string())
+    }
+}
+
+impl Into<Header<'_>> for CacheControl {
+    fn into(self) -> Header<'static> {
+        Header::new("cache-control", self.0)
+    }
+}
+
+#[derive(Responder)]
+pub struct CachedResponder<R> {
+    inner: R,
+    cachecontrol: CacheControl,
+}
+
+impl<'r, 'o: 'r, R: Responder<'r, 'o>> CachedResponder<R> {
+    fn wrap(inner: R, policy: String) -> CachedResponder<R> {
+        CachedResponder {
+            inner: inner,
+            cachecontrol: CacheControl(policy),
+        }
+    }
+}
+
+#[derive(Clone)]
+pub struct CachedHandler<H: Clone> {
+    inner: H,
+    cachecontrol: CacheControl,
+}
+
+unsafe impl<H: Clone + Send> Send for CachedHandler<H> {}
+unsafe impl<H: Clone + Sync> Sync for CachedHandler<H> {}
+
+impl<H: Clone + Handler> CachedHandler<H> {
+    pub fn wrap(inner: H, policy: CacheControl) -> CachedHandler<H> {
+        CachedHandler {
+            inner: inner,
+            cachecontrol: policy,
+        }
+    }
+}
+
+impl<H: Clone + Handler + Into<Vec<Route>>> Into<Vec<Route>> for CachedHandler<H> {
+    fn into(self) -> Vec<Route> {
+        // bah
+        let mut r = self.inner.clone().into();
+        assert_eq!(r.len(), 1);
+        r[0].handler = Box::new(self);
+        r
+    }
+}
+
+#[rocket::async_trait]
+impl<H: Clone + Handler> Handler for CachedHandler<H> {
+    async fn handle<'r>(&self, req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r> {
+        info!("Received request {:?}", req);
+        match self.inner.handle(req, data).await {
+            Outcome::Success(mut resp) => {
+                resp.set_header(Header::new("cache-control", self.cachecontrol.0.clone()));
+                Outcome::Success(resp)
+            }
+            o => o,
+        }
+    }
+}
--- a/src/main.rs	Sat Jul 16 10:45:58 2022 -0700
+++ b/src/main.rs	Sat Jul 16 13:20:20 2022 -0700
@@ -1,3 +1,4 @@
+mod cacheresponder;
 mod configdb;
 mod db;
 mod fromparam;
@@ -434,12 +435,6 @@
         .extract::<CustomConfig>()
         .expect("custom config");
 
-    let ap = Path::new(cfg.asset_path.as_str());
-    let ap = ap
-        .canonicalize()
-        .expect("absolute path to asset directory")
-        .to_path_buf();
-
     let geoip = match crate::geoip::GeoIP::new(cfg.geodb_path) {
         Ok(g) => Some(g),
         Err(e) => {
@@ -448,13 +443,23 @@
         }
     };
 
+    let ap = Path::new(cfg.asset_path.as_str());
+    let ap = ap
+        .canonicalize()
+        .expect("absolute path to asset directory")
+        .to_path_buf();
+    let fileserver = cacheresponder::CachedHandler::wrap(
+        FileServer::from(ap),
+        cacheresponder::CacheControl::new("max-age=43200"),
+    );
+
     let r = r
         .attach(ConfigDB::init())
         .attach(LogsDB::init())
         .attach(Template::fairing())
         .attach(rocket::fairing::AdHoc::config::<CustomConfig>())
         .manage(geoip)
-        .mount("/static", FileServer::from(ap))
+        .mount("/static", fileserver)
         .mount(
             "/",
             rocket::routes![