From 3b3eaa609aeddf817dfd9decb431835842980b74 Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Sun, 14 Jun 2026 14:15:22 +0800 Subject: [PATCH] fix(listener/pht): set X-Accel-Buffering to fix hang behind Nginx (issue #721) The /pull handler streams data as base64 chunks with a flush per chunk. With Nginx proxy_buffering on (the default), these tiny chunks and the heartbeat newlines are buffered and never flushed to the client, so active data transfer hangs until the buffer fills or the upstream closes. Set X-Accel-Buffering: no on the pull response so Nginx forwards each flushed chunk immediately without buffering. Nginx consumes the header (it is not forwarded to the client) and it is inert when no proxy sits in front of the listener, so it is safe to set unconditionally. Covers pht, phts and h3, which share the same Server handler. --- internal/util/pht/server.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/util/pht/server.go b/internal/util/pht/server.go index 42a006a0..c88eb3d5 100644 --- a/internal/util/pht/server.go +++ b/internal/util/pht/server.go @@ -365,6 +365,11 @@ func (s *Server) handlePull(w http.ResponseWriter, r *http.Request) { conn := v.(net.Conn) + // Disable per-response buffering so streaming proxies forward each flushed + // chunk immediately. Without this, Nginx with proxy_buffering on (the + // default) holds the tiny streamed chunks in its buffer and the response + // hangs until the buffer fills or the connection closes. (issue #721) + w.Header().Set("X-Accel-Buffering", "no") w.WriteHeader(http.StatusOK) if fw, ok := w.(http.Flusher); ok { fw.Flush()