bobashare_web/
static_routes.rs

1//! Handler to serve static files
2
3use axum::response::IntoResponse;
4use hyper::{header, HeaderMap, StatusCode, Uri};
5use rust_embed::RustEmbed;
6use tracing::{event, instrument, Level};
7
8#[derive(RustEmbed)]
9#[folder = "static/"]
10struct Asset;
11
12#[instrument(skip(headers), fields(if_none_match = ?headers.get(header::IF_NONE_MATCH)))]
13pub async fn handler(uri: Uri, headers: HeaderMap) -> impl IntoResponse {
14    let path = uri.path().trim_start_matches('/');
15    event!(Level::DEBUG, ?path);
16
17    match Asset::get(path) {
18        None => {
19            event!(Level::WARN, path, "file not found");
20            (StatusCode::NOT_FOUND, "404 Not Found").into_response()
21        }
22        Some(f) => {
23            let sha256 = hex::encode(f.metadata.sha256_hash());
24            event!(Level::TRACE, sha256);
25            if cfg!(not(debug_assertions)) {
26                if let Some(tag) = headers.get(header::IF_NONE_MATCH) {
27                    event!(Level::TRACE, ?tag);
28                    // XXX: cool, a new let-else
29                    let Ok(tag) = tag.to_str() else {
30                        return (StatusCode::BAD_REQUEST, "invalid ETag").into_response();
31                    };
32                    if tag == sha256 {
33                        return (StatusCode::NOT_MODIFIED, "").into_response();
34                    }
35                }
36            }
37
38            let mimetype = f.metadata.mimetype();
39            event!(Level::DEBUG, ?sha256, ?mimetype);
40            (
41                [
42                    (header::ACCESS_CONTROL_ALLOW_ORIGIN, "*".to_string()),
43                    (header::CACHE_CONTROL, "no-cache".to_string()),
44                    (header::CONTENT_TYPE, mimetype.to_string()),
45                    (header::ETAG, sha256),
46                ],
47                f.data,
48            )
49                .into_response()
50        }
51    }
52}