From 88e210daaf0a364bf68145d493ac5e104a5e3ced Mon Sep 17 00:00:00 2001 From: Petr Date: Tue, 30 Jun 2026 14:01:11 +0200 Subject: [PATCH] fix(gopher): bound cancel goroutine to Download lifetime --- internal/protocol/gopher/gopher.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/internal/protocol/gopher/gopher.go b/internal/protocol/gopher/gopher.go index 17dd57b..6cfdc65 100644 --- a/internal/protocol/gopher/gopher.go +++ b/internal/protocol/gopher/gopher.go @@ -83,10 +83,18 @@ func (p *Protocol) Download(ctx context.Context, req *core.DownloadRequest) (*co // Close the connection when the context is cancelled so any // blocking Read returns immediately instead of waiting for the - // 30-second deadline. + // dial deadline. The done channel bounds the goroutine to the + // lifetime of Download: the goroutine exits either when the + // context fires (we close the conn) or when Download returns + // successfully and defer close(done) signals shutdown. + done := make(chan struct{}) + defer close(done) go func() { - <-ctx.Done() - conn.Close() + select { + case <-ctx.Done(): + conn.Close() + case <-done: + } }() // Send selector + CRLF