This commit is contained in:
gru committed 2026-10-03 00:27:09 +01:00
commit 5e23e9af02
240 files changed
+99957

No files matched your search

+108
View File
@@ -0,0 +1,108 @@
//! Separate opt-in HTTP backend, not a shortcut inside the proxy handler.
use axum::{
body::Body,
extract::Request,
response::{Html, IntoResponse, Response},
routing::{any, get},
Json, Router,
};
use bytes::Bytes;
use http::HeaderMap;
use serde_json::json;
use std::{convert::Infallible, time::Duration};
pub fn router() -> Router {
Router::new()
.route(
"/",
get(|| async { Html(include_str!("admin/web/demo.html")) }),
)
.route("/ws", get(websocket))
.route("/cache-demo", get(cache_demo))
.route("/inspect", any(inspect))
.route("/echo", any(echo))
.route("/stream", get(stream))
.fallback(|| async {
Json(json!({"backend":"demo","message":"Request reached the separate demo backend."}))
})
}
async fn inspect(request: Request) -> Json<serde_json::Value> {
let headers = request.headers();
let read = |name: &str| {
headers
.get(name)
.and_then(|v| v.to_str().ok())
.unwrap_or("")
.to_owned()
};
Json(
json!({"backend":"demo", "method":request.method().as_str(), "path":request.uri().path(),
"query":request.uri().query(), "http_version":format!("{:?}", request.version()), "host":read("host"), "forwarded_for":read("x-forwarded-for"),
"forwarded_proto":read("x-forwarded-proto"), "request_id":read("x-request-id")}),
)
}
async fn echo(request: Request) -> Response {
let content_type = request.headers().get("content-type").cloned();
let mut response = request.into_body().into_response();
if let Some(value) = content_type {
response.headers_mut().insert("content-type", value);
}
response
}
async fn stream() -> (HeaderMap, Body) {
let stream = futures_util::stream::unfold(0u32, |index| async move {
if index >= 8 {
return None;
}
tokio::time::sleep(Duration::from_millis(300)).await;
Some((
Ok::<_, Infallible>(Bytes::from(format!(
"chunk={} backend=demo streaming=true\n",
index + 1
))),
index + 1,
))
});
let mut headers = HeaderMap::new();
headers.insert("content-type", "text/plain; charset=utf-8".parse().unwrap());
headers.insert("cache-control", "no-store".parse().unwrap());
(headers, Body::from_stream(stream))
}
async fn websocket(ws: axum::extract::ws::WebSocketUpgrade) -> Response {
use axum::extract::ws::Message;
ws.max_message_size(65_536)
.max_frame_size(65_536)
.on_upgrade(|mut socket| async move {
while let Some(Ok(message)) = socket.recv().await {
let reply = match message {
Message::Text(_) | Message::Binary(_) => message,
Message::Ping(data) => Message::Pong(data),
Message::Pong(_) => continue,
Message::Close(frame) => {
let _ = socket.send(Message::Close(frame)).await;
break;
}
};
if socket.send(reply).await.is_err() {
break;
}
}
})
}
/// Explicitly public demo object for manual cache/compression checks; no request secrets.
async fn cache_demo() -> Response {
let now = crate::logging::now_ms();
let text = format!(
"RustProxy public cache demo. Origin generation time: {now} ms\n{}",
"This is an anonymous demo object, fresh for 30 seconds.\n".repeat(100)
);
(
[
("cache-control", "public, max-age=30"),
("content-type", "text/plain; charset=utf-8"),
],
text,
)
.into_response()
}