Rewrite CDN URLs to local paths when serving HTML
- Added rewrite_cdn_urls() to replace HTMX CDN URLs with /js/vendor/htmx.min.js - Applied to both MinIO and filesystem serving paths - Supports unpkg.com, jsdelivr, cdnjs variants - Ensures old apps with CDN references work with local files
This commit is contained in:
parent
2f045bffa5
commit
762620f7a9
1 changed files with 50 additions and 13 deletions
|
|
@ -11,6 +11,24 @@ use axum::{
|
||||||
use log::{error, info, trace, warn};
|
use log::{error, info, trace, warn};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// Rewrite CDN URLs to local paths for HTMX and other vendor libraries
|
||||||
|
/// This ensures old apps with CDN references still work with local files
|
||||||
|
fn rewrite_cdn_urls(html: &str) -> String {
|
||||||
|
html
|
||||||
|
// HTMX from various CDNs
|
||||||
|
.replace("https://unpkg.com/htmx.org@1.9.10", "/js/vendor/htmx.min.js")
|
||||||
|
.replace("https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js", "/js/vendor/htmx.min.js")
|
||||||
|
.replace("https://unpkg.com/htmx.org@1.9.11", "/js/vendor/htmx.min.js")
|
||||||
|
.replace("https://unpkg.com/htmx.org@1.9.11/dist/htmx.min.js", "/js/vendor/htmx.min.js")
|
||||||
|
.replace("https://unpkg.com/htmx.org@1.9.12", "/js/vendor/htmx.min.js")
|
||||||
|
.replace("https://unpkg.com/htmx.org@1.9.12/dist/htmx.min.js", "/js/vendor/htmx.min.js")
|
||||||
|
.replace("https://unpkg.com/htmx.org", "/js/vendor/htmx.min.js")
|
||||||
|
.replace("https://cdn.jsdelivr.net/npm/htmx.org", "/js/vendor/htmx.min.js")
|
||||||
|
.replace("https://cdnjs.cloudflare.com/ajax/libs/htmx/1.9.10/htmx.min.js", "/js/vendor/htmx.min.js")
|
||||||
|
.replace("https://cdnjs.cloudflare.com/ajax/libs/htmx/1.9.11/htmx.min.js", "/js/vendor/htmx.min.js")
|
||||||
|
.replace("https://cdnjs.cloudflare.com/ajax/libs/htmx/1.9.12/htmx.min.js", "/js/vendor/htmx.min.js")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn configure_app_server_routes() -> Router<Arc<AppState>> {
|
pub fn configure_app_server_routes() -> Router<Arc<AppState>> {
|
||||||
Router::new()
|
Router::new()
|
||||||
// Serve app files: /apps/{app_name}/* (clean URLs)
|
// Serve app files: /apps/{app_name}/* (clean URLs)
|
||||||
|
|
@ -110,11 +128,20 @@ async fn serve_app_file_internal(state: &AppState, app_name: &str, file_path: &s
|
||||||
let content = body.into_bytes();
|
let content = body.into_bytes();
|
||||||
let content_type = get_content_type(&sanitized_file_path);
|
let content_type = get_content_type(&sanitized_file_path);
|
||||||
|
|
||||||
|
// For HTML files, rewrite CDN URLs to local paths
|
||||||
|
let final_content = if content_type.starts_with("text/html") {
|
||||||
|
let html = String::from_utf8_lossy(&content);
|
||||||
|
let rewritten = rewrite_cdn_urls(&html);
|
||||||
|
rewritten.into_bytes()
|
||||||
|
} else {
|
||||||
|
content.to_vec()
|
||||||
|
};
|
||||||
|
|
||||||
return Response::builder()
|
return Response::builder()
|
||||||
.status(StatusCode::OK)
|
.status(StatusCode::OK)
|
||||||
.header(header::CONTENT_TYPE, content_type)
|
.header(header::CONTENT_TYPE, content_type)
|
||||||
.header(header::CACHE_CONTROL, "public, max-age=3600")
|
.header(header::CACHE_CONTROL, "public, max-age=3600")
|
||||||
.body(Body::from(content.to_vec()))
|
.body(Body::from(final_content))
|
||||||
.unwrap_or_else(|_| {
|
.unwrap_or_else(|_| {
|
||||||
(StatusCode::INTERNAL_SERVER_ERROR, "Failed to build response")
|
(StatusCode::INTERNAL_SERVER_ERROR, "Failed to build response")
|
||||||
.into_response()
|
.into_response()
|
||||||
|
|
@ -154,18 +181,28 @@ async fn serve_app_file_internal(state: &AppState, app_name: &str, file_path: &s
|
||||||
let content_type = get_content_type(&sanitized_file_path);
|
let content_type = get_content_type(&sanitized_file_path);
|
||||||
|
|
||||||
match std::fs::read(&full_path) {
|
match std::fs::read(&full_path) {
|
||||||
Ok(contents) => Response::builder()
|
Ok(contents) => {
|
||||||
.status(StatusCode::OK)
|
// For HTML files, rewrite CDN URLs to local paths
|
||||||
.header(header::CONTENT_TYPE, content_type)
|
let final_content = if content_type.starts_with("text/html") {
|
||||||
.header(header::CACHE_CONTROL, "public, max-age=3600")
|
let html = String::from_utf8_lossy(&contents);
|
||||||
.body(Body::from(contents))
|
rewrite_cdn_urls(&html).into_bytes()
|
||||||
.unwrap_or_else(|_| {
|
} else {
|
||||||
(
|
contents
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
};
|
||||||
"Failed to build response",
|
|
||||||
)
|
Response::builder()
|
||||||
.into_response()
|
.status(StatusCode::OK)
|
||||||
}),
|
.header(header::CONTENT_TYPE, content_type)
|
||||||
|
.header(header::CACHE_CONTROL, "public, max-age=3600")
|
||||||
|
.body(Body::from(final_content))
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
"Failed to build response",
|
||||||
|
)
|
||||||
|
.into_response()
|
||||||
|
})
|
||||||
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to read file {full_path}: {e}");
|
error!("Failed to read file {full_path}: {e}");
|
||||||
(StatusCode::INTERNAL_SERVER_ERROR, "Failed to read file").into_response()
|
(StatusCode::INTERNAL_SERVER_ERROR, "Failed to read file").into_response()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue