use actix_web::{http::header, web, HttpRequest, HttpResponse}; use mime_guess2::MimeGuess; fn cache_control_header(path: &str) -> &'static str { if path == "index.html" { "no-cache, no-store, must-revalidate" } else if path.ends_with(".js") || path.ends_with(".css") || path.ends_with(".woff2") || path.ends_with(".woff") || path.ends_with(".ttf") || path.ends_with(".otf") || path.ends_with(".png") || path.ends_with(".jpg") || path.ends_with(".jpeg") || path.ends_with(".gif") || path.ends_with(".svg") || path.ends_with(".ico") || path.ends_with(".webp") || path.ends_with(".avif") || path.ends_with(".map") { "public, max-age=31536000, immutable" } else { "no-cache" } } pub async fn serve_frontend(req: HttpRequest, path: web::Path) -> HttpResponse { let path = path.into_inner(); let path_str = if path.is_empty() || path == "/" { "index.html" } else { path.as_str() }; let cc = cache_control_header(path_str); match frontend::get_frontend_asset_with_etag(path_str) { Some((data, etag)) => { // Check If-None-Match for conditional request if let Some(if_none_match) = req.headers().get(header::IF_NONE_MATCH) { if let Ok(client_etag) = if_none_match.to_str() { if client_etag == etag { return HttpResponse::NotModified() .insert_header(("Cache-Control", cc)) .insert_header(("ETag", etag)) .finish(); } } } let mime = MimeGuess::from_path(path_str).first_or_octet_stream(); HttpResponse::Ok() .content_type(mime.as_ref()) .insert_header(("Cache-Control", cc)) .insert_header(("ETag", etag)) .body(data.to_vec()) } None => match frontend::get_frontend_asset_with_etag("index.html") { Some((data, etag)) => HttpResponse::Ok() .content_type("text/html") .insert_header(("Cache-Control", "no-cache, no-store, must-revalidate")) .insert_header(("ETag", etag)) .body(data.to_vec()), None => HttpResponse::NotFound().finish(), }, } }