mirror of
https://github.com/Xevion/banner.git
synced 2025-12-08 16:06:31 -06:00
feat: cache mime types for valid assets, use octet-stream content type
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -218,7 +218,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "banner"
|
name = "banner"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "banner"
|
name = "banner"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
default-run = "banner"
|
default-run = "banner"
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,9 @@
|
|||||||
//! This module handles serving static assets that are embedded into the binary
|
//! This module handles serving static assets that are embedded into the binary
|
||||||
//! at compile time using rust-embed.
|
//! at compile time using rust-embed.
|
||||||
|
|
||||||
use axum::{
|
use dashmap::DashMap;
|
||||||
extract::Path,
|
use once_cell::sync::Lazy;
|
||||||
http::{StatusCode, header},
|
|
||||||
response::{Html, IntoResponse, Response},
|
|
||||||
};
|
|
||||||
use rust_embed::RustEmbed;
|
use rust_embed::RustEmbed;
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
/// Embedded web assets from the dist directory
|
/// Embedded web assets from the dist directory
|
||||||
#[derive(RustEmbed)]
|
#[derive(RustEmbed)]
|
||||||
@@ -18,18 +14,24 @@ use tracing::debug;
|
|||||||
#[exclude = "*.map"]
|
#[exclude = "*.map"]
|
||||||
pub struct WebAssets;
|
pub struct WebAssets;
|
||||||
|
|
||||||
const ASSET_EXTENSIONS: &[&str] = &[
|
/// Global cache for MIME types to avoid repeated mime_guess lookups
|
||||||
"js", "css", "png", "jpg", "jpeg", "gif", "svg", "ico", "woff", "woff2", "ttf", "eot",
|
static MIME_CACHE: Lazy<DashMap<String, Option<String>>> = Lazy::new(DashMap::new);
|
||||||
];
|
|
||||||
|
|
||||||
/// Check if a path should be served as a static asset
|
/// Get cached MIME type for a file path, caching on-demand
|
||||||
pub fn is_asset_path(path: &str) -> bool {
|
/// Returns None if the MIME type is text/plain or if no MIME type could be determined
|
||||||
if !path.starts_with("/assets/") {
|
pub fn get_mime_type_cached(path: &str) -> Option<String> {
|
||||||
return path.eq("index.html");
|
// Check cache first
|
||||||
|
if let Some(cached) = MIME_CACHE.get(path) {
|
||||||
|
return cached.value().as_ref().cloned();
|
||||||
}
|
}
|
||||||
|
|
||||||
match path.split_once('.') {
|
// Perform MIME guess and cache the result
|
||||||
Some((_, extension)) => ASSET_EXTENSIONS.contains(&extension),
|
let result = mime_guess::from_path(path)
|
||||||
None => false,
|
.first()
|
||||||
}
|
.map(|mime| mime.to_string());
|
||||||
|
|
||||||
|
// Cache the result
|
||||||
|
MIME_CACHE.insert(path.to_string(), result.clone());
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ use tower_http::{
|
|||||||
cors::{Any, CorsLayer},
|
cors::{Any, CorsLayer},
|
||||||
trace::TraceLayer,
|
trace::TraceLayer,
|
||||||
};
|
};
|
||||||
use tracing::{debug, info};
|
use tracing::info;
|
||||||
|
|
||||||
use crate::web::assets::WebAssets;
|
use crate::web::assets::{WebAssets, get_mime_type_cached};
|
||||||
|
|
||||||
use crate::banner::BannerApi;
|
use crate::banner::BannerApi;
|
||||||
|
|
||||||
@@ -82,9 +82,19 @@ async fn handle_spa_fallback(uri: Uri) -> Response {
|
|||||||
let path = uri.path().trim_start_matches('/');
|
let path = uri.path().trim_start_matches('/');
|
||||||
|
|
||||||
if let Some(content) = WebAssets::get(path) {
|
if let Some(content) = WebAssets::get(path) {
|
||||||
let mime_type = mime_guess::from_path(path).first_or_text_plain();
|
|
||||||
let data = content.data.to_vec();
|
let data = content.data.to_vec();
|
||||||
return ([(header::CONTENT_TYPE, mime_type.as_ref())], data).into_response();
|
|
||||||
|
// Use cached MIME type, only set Content-Type if we have a valid MIME type
|
||||||
|
let mime_type = get_mime_type_cached(path);
|
||||||
|
return (
|
||||||
|
[(
|
||||||
|
header::CONTENT_TYPE,
|
||||||
|
// For unknown types, set to application/octet-stream
|
||||||
|
mime_type.unwrap_or("application/octet-stream".to_string()),
|
||||||
|
)],
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
.into_response();
|
||||||
} else {
|
} else {
|
||||||
// Any assets that are not found should be treated as a 404, not falling back to the SPA index.html
|
// Any assets that are not found should be treated as a 404, not falling back to the SPA index.html
|
||||||
if path.starts_with("assets/") {
|
if path.starts_with("assets/") {
|
||||||
|
|||||||
Reference in New Issue
Block a user