Skip to content

Commit 18e62d8

Browse files
committed
feat: Implement basic HTTP caching with ETag and Last-Modified
This commit introduces handling for `If-None-Match` and `If-Modified-Since` headers. - Adds `ETag` and `Last-Modified` headers to the response. - Checks for `If-None-Match` and `If-Modified-Since` in the request headers. - Returns a `304 Not Modified` response if the cache is still valid. Signed-off-by: Denys Fedoryshchenko <denys.f@collabora.com>
1 parent 504edcd commit 18e62d8

1 file changed

Lines changed: 39 additions & 0 deletions

File tree

src/main.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,44 @@ async fn ax_get_file(
571571
);
572572

573573
headers.insert(header::ACCEPT_RANGES, "bytes".parse().unwrap());
574+
// add e-tag header from received_file.headers
575+
if let Some(etag) = upstream_headers.get("ETag") {
576+
headers.insert(header::ETAG, etag.clone());
577+
}
578+
// add last-modified header
579+
if let Some(last_modified) = upstream_headers.get("Last-Modified") {
580+
headers.insert(header::LAST_MODIFIED, last_modified.clone());
581+
}
582+
583+
// TODO: rxheaders.get is case sensitive or not?
584+
// Does request have If-None-Match header?
585+
if let Some(if_none_match) = rxheaders.get("If-None-Match") {
586+
// §13.1.2, last paragraph, RFC 9110
587+
if method != axum::http::Method::GET && method != axum::http::Method::HEAD {
588+
return (StatusCode::PRECONDITION_FAILED, "Method Not Allowed").into_response();
589+
}
590+
if let Some(etag) = upstream_headers.get("ETag") {
591+
if if_none_match == etag {
592+
println!(
593+
"{:?} 304 0 {} {} {} {}",
594+
remote_addr, human_time, method, filepath, user_agent_str
595+
);
596+
return (StatusCode::NOT_MODIFIED, headers, Body::empty()).into_response();
597+
}
598+
}
599+
// Does request have If-Modified-Since header?
600+
} else if let Some(if_modified_since) = rxheaders.get("If-Modified-Since") {
601+
if let Some(last_modified) = upstream_headers.get("Last-Modified") {
602+
// TODO: Validate properly last_modified
603+
if if_modified_since == last_modified {
604+
println!(
605+
"{:?} 304 0 {} {} {} {}",
606+
remote_addr, human_time, method, filepath, user_agent_str
607+
);
608+
return (StatusCode::NOT_MODIFIED, headers, Body::empty()).into_response();
609+
}
610+
}
611+
}
574612

575613
/* Usually HEAD is used to check if the file exists and range is supported */
576614
if method == axum::http::Method::HEAD {
@@ -581,6 +619,7 @@ async fn ax_get_file(
581619
);
582620
return (headers, Body::empty()).into_response();
583621
}
622+
584623
match tokio::fs::File::open(&cached_file).await {
585624
Ok(mut file) => {
586625
let mut start = 0;

0 commit comments

Comments
 (0)