From 91b33cf5914cb3a67e6f551b7b3414615b6740e8 Mon Sep 17 00:00:00 2001 From: Marius Goetze Date: Tue, 11 Mar 2025 14:32:09 +0100 Subject: [PATCH] fix: fix memory leak on failed http requests In many error cases the http response body was not closed as the `defer` statement was only executed after the error handling. Thus the connection can't be reused. This caused the creation of many goroutines, massively increasing the memory consumption. A prominent scenario is if a CSAF provider does not provide both sha256 and sha512 checksums. --- cmd/csaf_downloader/downloader.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/cmd/csaf_downloader/downloader.go b/cmd/csaf_downloader/downloader.go index 3270a88c..f9ea8402 100644 --- a/cmd/csaf_downloader/downloader.go +++ b/cmd/csaf_downloader/downloader.go @@ -484,6 +484,15 @@ nextAdvisory: "error", err) continue } + responseBody, err := io.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + stats.downloadFailed++ + slog.Warn("Cannot read response body", + "url", file.URL(), + "error", err) + continue + } if resp.StatusCode != http.StatusOK { stats.downloadFailed++ @@ -556,8 +565,7 @@ nextAdvisory: var doc any if err := func() error { - defer resp.Body.Close() - tee := io.TeeReader(resp.Body, hasher) + tee := io.TeeReader(bytes.NewReader(responseBody), hasher) return json.NewDecoder(tee).Decode(&doc) }(); err != nil { stats.downloadFailed++ @@ -758,11 +766,11 @@ func loadSignature(client util.Client, p string) (*crypto.PGPSignature, []byte, if err != nil { return nil, nil, err } + defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, nil, fmt.Errorf( "fetching signature from '%s' failed: %s (%d)", p, resp.Status, resp.StatusCode) } - defer resp.Body.Close() data, err := io.ReadAll(resp.Body) if err != nil { return nil, nil, err @@ -823,11 +831,11 @@ func loadHash(client util.Client, p string) ([]byte, []byte, error) { if err != nil { return nil, nil, err } + defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, nil, fmt.Errorf( "fetching hash from '%s' failed: %s (%d)", p, resp.Status, resp.StatusCode) } - defer resp.Body.Close() var data bytes.Buffer tee := io.TeeReader(resp.Body, &data) hash, err := util.HashFromReader(tee)