Rust library to generate static websites
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(cli): Missing HTTP headers

+28 -34
+5
.sampo/changesets/heroic-iceseeker-nyyrikki.md
··· 1 + --- 2 + maudit-cli: patch 3 + --- 4 + 5 + Fixes missing HTTP headers on HTML responses
+2 -2
crates/maudit-cli/Cargo.toml
··· 19 19 "signal", 20 20 "process", 21 21 ] } 22 - axum = { version = "0.8.1", features = ["ws"] } 22 + axum = { version = "0.8.6", features = ["ws"] } 23 23 futures = "0.3" 24 - tower-http = { version = "0.6.2", features = ["fs", "trace"] } 24 + tower-http = { version = "0.6.6", features = ["fs", "trace"] } 25 25 tracing = "0.1" 26 26 tracing-subscriber = { version = "=0.3.19", features = [ 27 27 "env-filter",
+21 -32
crates/maudit-cli/src/dev/server.rs
··· 5 5 Request, State, 6 6 ws::{Message, WebSocket, WebSocketUpgrade}, 7 7 }, 8 - http::{HeaderValue, StatusCode, Uri}, 8 + http::{HeaderValue, StatusCode, header::CONTENT_LENGTH}, 9 9 middleware::{self, Next}, 10 10 response::{IntoResponse, Response}, 11 11 routing::get, ··· 17 17 signal, 18 18 sync::{RwLock, broadcast}, 19 19 }; 20 - use tracing::{Level, debug, warn}; 20 + use tracing::{Level, debug}; 21 21 22 22 use std::net::{IpAddr, SocketAddr}; 23 23 use std::sync::Arc; ··· 69 69 current_status: Arc<RwLock<Option<PersistentStatus>>>, 70 70 } 71 71 72 - fn inject_live_reload_script( 73 - uri: &Uri, 74 - html_content: &str, 75 - socket_addr: SocketAddr, 76 - host: bool, 77 - ) -> String { 72 + fn inject_live_reload_script(html_content: &str, socket_addr: SocketAddr, host: bool) -> String { 73 + let mut content = html_content.to_string(); 74 + 78 75 let script_content = include_str!(concat!(env!("OUT_DIR"), "/js/client.js")).replace( 79 76 "{SERVER_ADDRESS}", 80 77 &format!( ··· 88 85 ), 89 86 ); 90 87 91 - // Only inject script if content looks like proper HTML 92 - if html_content.trim_start().starts_with("<!DOCTYPE") 93 - || html_content.trim_start().starts_with("<html") 94 - { 95 - format!("{}<script>{}</script>", html_content, script_content) 96 - } else { 97 - warn!( 98 - "{} matched an HTML response, but it does not look like proper HTML, live-reload won't work. Make sure your HTML has a proper <!DOCTYPE> or <html> tag.", 99 - uri 100 - ); 101 - // Not proper HTML, return content unchanged 102 - html_content.to_string() 103 - } 88 + content.push_str(&format!("\n\n<script>{script_content}</script>")); 89 + content 104 90 } 105 91 106 92 pub async fn start_dev_web_server( ··· 124 110 }); 125 111 } 126 112 127 - async fn handle_404( 128 - uri: Uri, 129 - socket_addr: SocketAddr, 130 - host: bool, 131 - dist_dir: &str, 132 - ) -> impl IntoResponse { 113 + async fn handle_404(socket_addr: SocketAddr, host: bool, dist_dir: &str) -> impl IntoResponse { 133 114 let content = match fs::read_to_string(format!("{}/404.html", dist_dir)).await { 134 115 Ok(custom_content) => custom_content, 135 116 Err(_) => include_str!("./404.html").to_string(), ··· 138 119 ( 139 120 StatusCode::NOT_FOUND, 140 121 [(header::CONTENT_TYPE, "text/html; charset=utf-8")], 141 - inject_live_reload_script(&uri, &content, socket_addr, host), 122 + inject_live_reload_script(&content, socket_addr, host), 142 123 ) 143 124 .into_response() 144 125 } ··· 162 143 debug!("listening on {}", listener.local_addr().unwrap()); 163 144 164 145 let serve_dir = 165 - ServeDir::new(dist_dir).not_found_service(axum::routing::any(move |uri: Uri| async move { 166 - handle_404(uri, socket_addr, host, dist_dir).await 146 + ServeDir::new(dist_dir).not_found_service(axum::routing::any(move || async move { 147 + handle_404(socket_addr, host, dist_dir).await 167 148 })); 168 149 169 150 // TODO: Return a `.well-known/appspecific/com.chrome.devtools.json` for Chrome ··· 254 235 if res.headers().get(axum::http::header::CONTENT_TYPE) 255 236 == Some(&HeaderValue::from_static("text/html")) 256 237 { 238 + let original_headers = res.headers().clone(); 257 239 let body = res.into_body(); 258 240 let bytes = to_bytes(body, usize::MAX).await.unwrap(); 259 241 260 242 let body = String::from_utf8_lossy(&bytes).into_owned(); 261 243 262 - let body_with_script = inject_live_reload_script(&uri, &body, socket_addr, host); 244 + let body_with_script = inject_live_reload_script(&body, socket_addr, host); 245 + let new_body_length = body_with_script.len(); 263 246 264 247 // Copy the headers from the original response 265 248 let mut res = Response::new(body_with_script.into()); 266 - *res.headers_mut() = res.headers().clone(); 249 + *res.headers_mut() = original_headers; 250 + 251 + // Update Content-Length header to match new body size 252 + res.headers_mut().insert( 253 + CONTENT_LENGTH, 254 + HeaderValue::from_str(&new_body_length.to_string()).unwrap(), 255 + ); 267 256 268 257 res.extensions_mut().insert(uri); 269 258