feat: router middleware (CORS, body limit, timeout, compression, tracing)

Layer global middleware onto build_router (applies to every route, shared by
main + the test harness):
- CORS: configurable allowed origins via CORS_ALLOWED_ORIGINS; empty -> allow
  any origin, which is safe here because auth is a Bearer token (no cookies, no
  ambient credentials). Credentials are never allowed.
- Body limit: 1 MiB global backstop (handlers already validate tighter per
  field); /wallet/lws/submit_tx overrides to ~2 MiB+ for raw Monero tx hex.
- Timeout: 60s request backstop (above the chain clients' ~30s timeouts, so
  their errors surface first; bounds any slow handler). Uses the http-aware
  tower_http TimeoutLayer (-> 408), not tower::timeout (fallible, rejected by
  axum's Infallible Router).
- gzip compression + request tracing (outermost).

Adds cors_allowed_origins config + the tower-http "timeout" feature. Per-IP
rate limiting is deliberately separate (needs ConnectInfo) — next commit.

All gates green; integration tests pass through the layered router (CORS/timeout/
compression/body-limit are oneshot-safe). openapi unchanged.
This commit is contained in:
jwinterm
2026-06-23 18:25:10 -04:00
parent 586f681287
commit 707613c92b
4 changed files with 65 additions and 3 deletions
+12 -2
View File
@@ -16,7 +16,12 @@
use std::sync::Arc;
use axum::{extract::State, http::HeaderMap, routing::post, Json, Router};
use axum::{
extract::{DefaultBodyLimit, State},
http::HeaderMap,
routing::post,
Json, Router,
};
use serde::{Deserialize, Serialize};
use tracing::instrument;
@@ -539,7 +544,12 @@ pub fn routes() -> Router<Arc<AppState>> {
.route("/wallet/lws/history", post(history))
.route("/wallet/lws/unspent_outs", post(unspent_outs))
.route("/wallet/lws/random_outs", post(random_outs))
.route("/wallet/lws/submit_tx", post(submit_tx))
// submit_tx carries a raw tx hex (up to MAX_CN_TX_HEX_LEN); raise its
// body cap above the global limit, with headroom for the JSON envelope.
.route(
"/wallet/lws/submit_tx",
post(submit_tx).layer(DefaultBodyLimit::max(MAX_CN_TX_HEX_LEN + 64 * 1024)),
)
.route("/wallet/lws/height", post(height))
.route("/wallet/lws/confirmations", post(confirmations))
}