From 54592bc8d0c9094dd301607e8a3fc9f3493b919c Mon Sep 17 00:00:00 2001 From: Vasilii Alferov Date: Thu, 7 May 2026 10:52:15 +0100 Subject: [PATCH] fix: close HTTP response bodies to prevent OOM with many checks When running 100+ HTTP checks concurrently, response bodies were never closed if the check only validated status and headers (no body matcher). This caused unclosed TCP connections to accumulate, holding TLS state and transport buffers until the 10s client timeout expired, leading to OOM kills under memory limits. Changes: - Add Close() to system.HTTP interface and DefHTTP - Track whether Body() consumed the response body - Close() closes resp.Body if it wasn't consumed (i.e. status/headers-only checks) - resource/http.go Validate() defers sysHTTP.Close() for guaranteed cleanup Fixes OOM when goss is configured with many HTTP checks and limited RAM. --- resource/http.go | 1 + system/http.go | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/resource/http.go b/resource/http.go index bbd82009..6ea4e385 100644 --- a/resource/http.go +++ b/resource/http.go @@ -78,6 +78,7 @@ func (u *HTTP) Validate(sys *system.System) []TestResult { RequestHeader: u.RequestHeader, RequestBody: u.RequestBody, Method: u.Method}) sysHTTP.SetAllowInsecure(u.AllowInsecure) sysHTTP.SetNoFollowRedirects(u.NoFollowRedirects) + defer sysHTTP.Close() var results []TestResult results = append(results, ValidateValue(u, "status", u.Status, sysHTTP.Status, skip)) diff --git a/system/http.go b/system/http.go index d5e5abec..e3053b3d 100644 --- a/system/http.go +++ b/system/http.go @@ -27,6 +27,7 @@ type HTTP interface { Exists() (bool, error) SetAllowInsecure(bool) SetNoFollowRedirects(bool) + Close() error } type DefHTTP struct { @@ -46,6 +47,7 @@ type DefHTTP struct { KeyFile string Method string Proxy string + bodyConsumed bool } func NewDefHTTP(_ context.Context, httpStr string, system *System, config util.Config) HTTP { @@ -214,10 +216,18 @@ func (u *DefHTTP) Body() (io.Reader, error) { if err := u.setup(); err != nil { return nil, err } + u.bodyConsumed = true return u.resp.Body, nil } +func (u *DefHTTP) Close() error { + if u.resp != nil && u.resp.Body != nil && !u.bodyConsumed { + return u.resp.Body.Close() + } + return nil +} + func hasUserAgentHeader(headers []string) bool { for _, header := range headers { if strings.HasPrefix(strings.ToLower(header), USER_AGENT_HEADER_PREFIX) {