d6e3189629cd24da158ca18f6f59494a3dd10a63
relayLogStream copied a pod-log follow to the client with a plain flusher.Flush per event. On a client that stays connected but stops reading (its TCP receive window shut), net/http buffers the small "data:" line and only touches the socket at Flush, which then blocks forever inside the write. The select's <-ctx.Done() branch is never reached, because r.Context() cancels on an actual disconnect, not on a stall, so the relay goroutine and its upstream apiserver follow leak for the life of the process. Route every event's write+flush through http.ResponseController with a per-write deadline (writeTimeout, 30s): a stalled flush now returns os.ErrDeadlineExceeded, the error plain http.Flusher.Flush swallows, and the relay abandons the stream so the deferred cancel + src.Close release the follow. SetWriteDeadline and rc.Flush are best-effort: a writer without deadline support (httptest recorder; some HTTP/2 origins) ignores the deadline and behaves exactly as before, so the guard degrades gracefully. This closes the leak the per-principal stream cap only bounded the blast radius of. Verified by a deterministic test with a deadline-aware ResponseWriter whose flush blocks until the deadline; the test times out (fails closed) if the guard is removed.
Languages
Go
62.7%
TypeScript
22.5%
Shell
7.4%
Java
7.1%
Dockerfile
0.2%
Other
0.1%