Make pipe read timeout configurable via idleTimeout metadata

The 30s hardcoded readTimeout in Pipe() caused all CONNECT tunnel
connections to be hard-closed after 30s of inactivity, breaking
WebSocket and long-polling connections through the proxy.

Pipe() now accepts a WithReadTimeout(d) option. When d is 0 (the
default) no read deadline is set, relying on TCP keepalives or context
cancellation to detect dead connections instead.

The HTTP handler exposes this as the idleTimeout metadata key.

Fixes: https://github.com/go-gost/x/issues/91
This commit is contained in:
Andrew Beresford
2026-05-08 11:31:53 +01:00
parent 07ca57055a
commit 290e9c37d5
3 changed files with 40 additions and 12 deletions
+3 -3
View File
@@ -428,7 +428,7 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
start := time.Now()
log.Infof("%s <-> %s", conn.RemoteAddr(), addr)
// xnet.Transport(conn, cc)
xnet.Pipe(ctx, conn, cc)
xnet.Pipe(ctx, conn, cc, xnet.WithReadTimeout(h.md.idleTimeout))
log.WithFields(map[string]any{
"duration": time.Since(start),
}).Infof("%s >-< %s", conn.RemoteAddr(), addr)
@@ -694,7 +694,7 @@ func (h *httpHandler) handleUpgradeResponse(ctx context.Context, rw io.ReadWrite
}
// return xnet.Transport(rw, backConn)
return xnet.Pipe(ctx, rw, backConn)
return xnet.Pipe(ctx, rw, backConn, xnet.WithReadTimeout(h.md.idleTimeout))
}
func (h *httpHandler) sniffingWebsocketFrame(ctx context.Context, rw, cc io.ReadWriter, ro *xrecorder.HandlerRecorderObject, log logger.Logger) error {
@@ -893,7 +893,7 @@ func (h *httpHandler) authenticate(ctx context.Context, conn net.Conn, req *http
req.Write(cc)
// xnet.Transport(conn, cc)
xnet.Pipe(ctx, conn, cc)
xnet.Pipe(ctx, conn, cc, xnet.WithReadTimeout(h.md.idleTimeout))
return
case "file":
f, _ := os.Open(pr.Value)