From de519edf789800f6102c1ac225e9febe8bfc4d5b Mon Sep 17 00:00:00 2001
From: Aiden McClelland <3732071+dr-bonez@users.noreply.github.com>
Date: Mon, 13 Mar 2023 17:25:10 -0600
Subject: [PATCH] fix caching (#2216)
---
backend/src/net/static_server.rs | 80 +++++++++++++++++++-------------
1 file changed, 49 insertions(+), 31 deletions(-)
diff --git a/backend/src/net/static_server.rs b/backend/src/net/static_server.rs
index da57b817f..c42c58079 100644
--- a/backend/src/net/static_server.rs
+++ b/backend/src/net/static_server.rs
@@ -10,6 +10,7 @@ use digest::Digest;
use futures::FutureExt;
use http::header::ACCEPT_ENCODING;
use http::header::CONTENT_ENCODING;
+use http::request::Parts as RequestParts;
use http::response::Builder;
use hyper::{Body, Method, Request, Response, StatusCode};
use openssl::hash::MessageDigest;
@@ -252,6 +253,7 @@ async fn alt_ui(req: Request
, ui_mode: UiMode) -> Result, E
let full_path = Path::new(selected_root_dir).join(uri_path);
file_send(
+ &request_parts,
if tokio::fs::metadata(&full_path)
.await
.ok()
@@ -298,6 +300,7 @@ async fn main_embassy_ui(req: Request, ctx: RpcContext) -> Result, ctx: RpcContext) -> Result Result, Error> {
}
async fn file_send(
+ req: &RequestParts,
path: impl AsRef,
accept_encoding: &[&str],
) -> Result, Error> {
@@ -421,40 +426,52 @@ async fn file_send(
.await
.with_ctx(|_| (ErrorKind::Filesystem, path.display().to_string()))?;
- match IsNonEmptyFile::new(&metadata, path) {
- Some(a) => a,
- None => return Ok(not_found()),
- };
+ let e_tag = e_tag(path, &metadata)?;
- let mut builder = Response::builder().status(StatusCode::OK);
- builder = with_e_tag(path, &metadata, builder)?;
+ let mut builder = Response::builder();
builder = with_content_type(path, builder);
- let body = if false && accept_encoding.contains(&"br") && metadata.len() > u16::MAX as u64 {
- builder = builder.header(CONTENT_ENCODING, "br");
- Body::wrap_stream(ReaderStream::new(BrotliEncoder::new(BufReader::new(file))))
- } else if accept_encoding.contains(&"gzip") && metadata.len() > u16::MAX as u64 {
- builder = builder.header(CONTENT_ENCODING, "gzip");
- Body::wrap_stream(ReaderStream::new(GzipEncoder::new(BufReader::new(file))))
- } else {
- builder = with_content_length(&metadata, builder);
- Body::wrap_stream(ReaderStream::new(file))
- };
- builder.body(body).with_kind(ErrorKind::Network)
-}
+ builder = builder.header(http::header::ETAG, &e_tag);
+ builder = builder.header(
+ http::header::CACHE_CONTROL,
+ "public, max-age=21000000, immutable",
+ );
-struct IsNonEmptyFile(());
-impl IsNonEmptyFile {
- fn new(metadata: &Metadata, path: &Path) -> Option {
- let length = metadata.len();
- if !metadata.is_file() || length == 0 {
- tracing::debug!("File is empty: {:?}", path);
- return None;
- }
- Some(Self(()))
+ if req
+ .headers
+ .get_all(http::header::CONNECTION)
+ .iter()
+ .flat_map(|s| s.to_str().ok())
+ .flat_map(|s| s.split(","))
+ .any(|s| s.trim() == "keep-alive")
+ {
+ builder = builder.header(http::header::CONNECTION, "keep-alive");
}
+
+ if req
+ .headers
+ .get("if-none-match")
+ .and_then(|h| h.to_str().ok())
+ == Some(e_tag.as_str())
+ {
+ builder = builder.status(StatusCode::NOT_MODIFIED);
+ builder.body(Body::empty())
+ } else {
+ let body = if false && accept_encoding.contains(&"br") && metadata.len() > u16::MAX as u64 {
+ builder = builder.header(CONTENT_ENCODING, "br");
+ Body::wrap_stream(ReaderStream::new(BrotliEncoder::new(BufReader::new(file))))
+ } else if accept_encoding.contains(&"gzip") && metadata.len() > u16::MAX as u64 {
+ builder = builder.header(CONTENT_ENCODING, "gzip");
+ Body::wrap_stream(ReaderStream::new(GzipEncoder::new(BufReader::new(file))))
+ } else {
+ builder = with_content_length(&metadata, builder);
+ Body::wrap_stream(ReaderStream::new(file))
+ };
+ builder.body(body)
+ }
+ .with_kind(ErrorKind::Network)
}
-fn with_e_tag(path: &Path, metadata: &Metadata, builder: Builder) -> Result {
+fn e_tag(path: &Path, metadata: &Metadata) -> Result {
let modified = metadata.modified().with_kind(ErrorKind::Filesystem)?;
let mut hasher = sha2::Sha256::new();
hasher.update(format!("{:?}", path).as_bytes());
@@ -469,11 +486,12 @@ fn with_e_tag(path: &Path, metadata: &Metadata, builder: Builder) -> Result Builder {
let content_type = match path.extension() {