milestone 17: real deadlines, validator holes, upstream editor, trusted proxies, contract samples, badvers
CI / test (push) Successful in 1m22s
CI / test-aarch64 (push) Successful in 4m55s
CI / frontend (push) Successful in 39s
CI / cross (push) Successful in 7m57s
CI / docker (push) Failing after 1h10m42s

This commit is contained in:
2026-08-07 17:55:59 +02:00
parent 9b12dbaaa0
commit c50c6d285a
57 changed files with 2926 additions and 126 deletions
+9 -4
View File
@@ -15,7 +15,9 @@
//!
//! The route is rate-limit exempt (a long-lived stream must not drain its
//! address's token bucket) but pays the per-address SSE connection cap, which
//! binds loopback too: hub slots are a fixed resource.
//! binds loopback too: hub slots are a fixed resource. The address it keys on is
//! `client_addr`, so behind a trusted proxy each remote client holds its own
//! budget rather than all of them sharing the proxy's.
const std = @import("std");
@@ -79,12 +81,15 @@ pub fn stream(
const hub = state.hub orelse
return http_util.respondError(request, .service_unavailable, "live stream unavailable");
const peer = address.NetAddress.fromIp(request.peer);
// The effective client, not the socket peer: behind a trusted proxy every
// stream would otherwise share one address's budget. Acquire and release
// read the same value, so a release can never miss the slot it took.
const client = address.NetAddress.fromIp(request.client_addr);
if (state.limiter) |limiter| {
if (!limiter.tryAcquireSse(io, std.Io.Clock.awake.now(io), peer))
if (!limiter.tryAcquireSse(io, std.Io.Clock.awake.now(io), client))
return http_util.respondError(request, .too_many_requests, "too many live streams from this address");
}
defer if (state.limiter) |limiter| limiter.releaseSse(io, peer);
defer if (state.limiter) |limiter| limiter.releaseSse(io, client);
const id = hub.subscribe(io) orelse
return http_util.respondError(request, .service_unavailable, "live stream is full");