diff options
Diffstat (limited to 'crates/chat-server/src/http.rs')
| -rw-r--r-- | crates/chat-server/src/http.rs | 56 |
1 files changed, 46 insertions, 10 deletions
diff --git a/crates/chat-server/src/http.rs b/crates/chat-server/src/http.rs index 1c7286f..7394b71 100644 --- a/crates/chat-server/src/http.rs +++ b/crates/chat-server/src/http.rs @@ -17,9 +17,10 @@ use crate::service::Service; use anyhow::Result; use axum::{ Json, Router, + body::Body, extract::{DefaultBodyLimit, State}, http::{HeaderMap, HeaderValue, StatusCode}, - response::{IntoResponse, Response}, + response::{IntoResponse, Redirect, Response}, routing::{get, post}, }; use serde_json::{Value, json}; @@ -93,6 +94,14 @@ async fn api(State(app): State<App>, headers: HeaderMap, Json(request): Json<Val } async fn asset(State(app): State<App>, uri: axum::http::Uri) -> Response { + if uri.path() == "/THIRD-PARTY-LICENSES.html" { + let Some(origin) = app.public.get("SITE_ORIGIN") else { + return secured(StatusCode::INTERNAL_SERVER_ERROR.into_response()); + }; + return secured( + Redirect::permanent(&format!("{origin}/THIRD-PARTY-LICENSES.html")).into_response(), + ); + } let (path, mime) = match uri.path() { "/" => ( "crates/chat-server/web/index.html", @@ -115,25 +124,33 @@ async fn asset(State(app): State<App>, uri: axum::http::Uri) -> Response { "text/css; charset=utf-8", ), "/crypto.wasm" => ( - "target/wasm32-wasip1/release/stack-chat-crypto.wasm", + if app.root.join("bin/chat/crypto.wasm").is_file() { + "bin/chat/crypto.wasm" + } else { + "target/wasm32-wasip1/release/stack-chat-crypto.wasm" + }, "application/wasm", ), "/javascript.html" => ( "crates/chat-server/web/javascript.html", "text/html; charset=utf-8", ), - "/SOURCE.tar.gz" => ("var/build/chat-source.tar.gz", "application/gzip"), - "/THIRD-PARTY-LICENSES.html" => { - ("web/THIRD-PARTY-LICENSES.html", "text/html; charset=utf-8") - } + "/SOURCE.tar.gz" => ( + if app.root.join("bin/chat/SOURCE.tar.gz").is_file() { + "bin/chat/SOURCE.tar.gz" + } else { + "var/build/chat-source.tar.gz" + }, + "application/gzip", + ), "/LIMITATIONS.txt" => ("docs/CHAT-APPLICATION.txt", "text/plain; charset=utf-8"), "/LICENSE" => ("LICENSE", "text/plain; charset=utf-8"), _ => return secured(StatusCode::NOT_FOUND.into_response()), }; - let Ok(bytes) = tokio::fs::read(app.root.join(path)).await else { - return secured(StatusCode::NOT_FOUND.into_response()); - }; if matches!(uri.path(), "/" | "/javascript.html") { + let Ok(bytes) = tokio::fs::read(app.root.join(path)).await else { + return secured(StatusCode::NOT_FOUND.into_response()); + }; let rendered = String::from_utf8(bytes) .map_err(anyhow::Error::from) .and_then(|source| stack_config::render(&source, &app.public)); @@ -142,7 +159,22 @@ async fn asset(State(app): State<App>, uri: axum::http::Uri) -> Response { |html| secured(([("content-type", mime)], html).into_response()), ); } - secured(([("content-type", mime)], bytes).into_response()) + let Ok(file) = tokio::fs::File::open(app.root.join(path)).await else { + return secured(StatusCode::NOT_FOUND.into_response()); + }; + let length = file.metadata().await.ok().map(|metadata| metadata.len()); + let mut response = Response::new(Body::from_stream(tokio_util::io::ReaderStream::new(file))); + response + .headers_mut() + .insert("content-type", HeaderValue::from_static(mime)); + if let Some(header_length) = + length.and_then(|value| HeaderValue::from_str(&value.to_string()).ok()) + { + response + .headers_mut() + .insert("content-length", header_length); + } + secured(response) } pub(crate) async fn serve( @@ -159,6 +191,10 @@ pub(crate) async fn serve( public, }; let routes = Router::new() + .route( + "/healthz", + get(|| async { secured("ok\n".into_response()) }), + ) .route("/api", post(api)) .fallback(get(asset)) .layer(DefaultBodyLimit::max(262_144)) |
