feat(websocket): write-progress timeout on the WS write pump (WS-18)

- DEFAULT_WS_WRITE_TIMEOUT (60 s, WS-01 knob family): one outbound WS
  send that stays unsent past the window (peer stopped reading)
  evicts the connection — the send path was slot-bounded but
  time-unbounded
- bound is per send call: a slow-but-draining peer resets it with
  every message emitted; only a fully stalled sink trips it
- on timeout the pump signals the stream error (InvalidData naming
  the write stall) and ends WITHOUT a close frame — a clogged socket
  cannot receive one and the close send would park on it
- test-support split helper with both knobs explicit backs the
  scaled eviction test (clogged duplex, eviction well inside the
  5 s slack)

Verification: scripts/verify.sh OK (343 passed), clippy -D warnings
clean, fmt clean
This commit is contained in:
2026-08-30 21:36:53 +00:00
parent d6d5509c6d
commit da65e5b6db
2 changed files with 186 additions and 8 deletions
+2 -2
View File
@@ -14,8 +14,8 @@ pub mod upgrade;
pub use byte_adapter::{
split_ws_to_bytes, split_ws_to_bytes_idle, WsByteStream, WsPumps, DEFAULT_WS_IDLE_TIMEOUT,
INBOUND_WS_FRAME_CAP, INBOUND_WS_MESSAGE_CAP, MAX_CHUNK_LEN, PENDING_BUFFER_CAP, WS_GOING_AWAY,
WS_MESSAGE_CAP, WS_PROTOCOL_ERROR,
DEFAULT_WS_WRITE_TIMEOUT, INBOUND_WS_FRAME_CAP, INBOUND_WS_MESSAGE_CAP, MAX_CHUNK_LEN,
PENDING_BUFFER_CAP, WS_GOING_AWAY, WS_MESSAGE_CAP, WS_PROTOCOL_ERROR,
};
#[cfg(any(test, feature = "wss"))]