Expand description
WebSocket reverse proxy.
WsProxy listens for incoming TCP connections, reads the initial HTTP
request, verifies it is a WebSocket upgrade, connects to a backend, performs
the WebSocket handshake end-to-end, and then bidirectionally tunnels raw
WebSocket bytes between the client and the backend.
Plain (ws://) backends use two threads (one per direction) via
std::io::copy, identical to the original implementation.
TLS (wss://) backends use a single-thread polling loop: both streams are
set to a 5 ms read timeout and the loop alternates between the two
directions, sleeping 1 ms when neither side has data. This avoids the
deadlock that arises when trying to share a rustls::StreamOwned between
two blocking threads.
§Health checks
WsProxy::new treats every configured backend as always live — matching
the original behavior, with no background monitoring. The config-driven
proxy’s [ws_proxy.health_check] (see spec/PROXY_SERVER_CONFIG.md) opts
a [[ws_proxy]] block into the same background health checker used for
[[upstream]] pools (proxy_config::health::start_health_checker), which
periodically probes each backend with a plain HTTP GET and removes it
from rotation after enough consecutive failures. If every backend is
currently unhealthy, new WebSocket upgrade attempts get 503 Service Unavailable instead of being routed to a backend known to be down.
§Example
use rust_web_server::ws_proxy::WsProxy;
// Plain WebSocket — two backends, round-robin.
WsProxy::new(["ws://chat-backend:9000", "ws://chat-backend:9001"])
.connect_timeout_ms(3000)
.bind("0.0.0.0:8080")
.unwrap();
// TLS WebSocket (requires http-client or http2 feature).
WsProxy::new(["wss://chat-backend.internal:443"])
.bind("0.0.0.0:8080")
.unwrap();Structs§
- WsProxy
- WebSocket reverse proxy with round-robin load balancing.