fix(collab-net): give a management request one deadline for its answer

reply read until the server answered, and every ping, pong or control
frame renewed the per-read timeout, so a library endpoint could hold a
background refresh (and the shared refresh permit) open indefinitely. The
whole exchange now ends at one absolute deadline, the idle timeout from
when the request went out.
This commit is contained in:
Dylan M. Taylor committed 2026-11-03 04:35:27 +00:00
1 parent 02c38a6d95
commit 31a60ed360
1 file changed
+8
+8
View File
@@ -206,7 +206,15 @@ fn send(ws: &mut Ws, msg: &ClientMsg) -> Result<(), String> {
/// The next answer `pick` takes, or why there is none.
fn reply<T>(ws: &mut Ws, limits: &NetLimits, pick: impl Fn(ServerMsg) -> Option<T>) -> Result<T, String> {
// One deadline for the whole answer: pings, pongs and a message trickling in each renew the
// read timeout, so without it a server could keep a request (and the refresh permit the
// caller holds) waiting for as long as it liked.
let until = std::time::Instant::now() + limits.idle_timeout;
ws.get_mut().read_until(Some(until));
loop {
if std::time::Instant::now() >= until {
return Err("no answer from the server (it took too long)".into());
}
return match ws.read() {
Ok(Message::Binary(b)) => match message::decode::<ServerMsg>(&b, limits.max_server_message) {
Ok(ServerMsg::Refused { reason }) => Err(format!("{REFUSED}{reason}")),