summaryrefslogtreecommitdiff
path: root/crates/chat-server/src/http.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/chat-server/src/http.rs')
-rw-r--r--crates/chat-server/src/http.rs56
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))