From cb2ee0a109512c01eea06bcb293d5b4688c7b099 Mon Sep 17 00:00:00 2001 From: omrzk <193513049+omrzk@users.noreply.github.com> Date: Sun, 25 Oct 2026 09:31:59 -0500 Subject: [PATCH] Keep response status pending after zero-byte ReadFrom --- capture_metrics.go | 4 +++- capture_metrics_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/capture_metrics.go b/capture_metrics.go index 97f0a51..74d7dd8 100644 --- a/capture_metrics.go +++ b/capture_metrics.go @@ -83,7 +83,9 @@ func (m *Metrics) CaptureMetrics(w http.ResponseWriter, fn func(http.ResponseWri return func(src io.Reader) (int64, error) { n, err := next(src) - headerWritten = true + if n > 0 { + headerWritten = true + } m.Written += n return n, err } diff --git a/capture_metrics_test.go b/capture_metrics_test.go index 222c8cb..3184723 100644 --- a/capture_metrics_test.go +++ b/capture_metrics_test.go @@ -1,6 +1,7 @@ package httpsnoop import ( + "errors" "io" "log" "net/http" @@ -8,6 +9,7 @@ import ( "os" "strings" "testing" + "testing/iotest" "time" ) @@ -61,6 +63,33 @@ func TestCaptureMetrics(t *testing.T) { WantWritten: 17, WantCode: http.StatusOK, }, + { + Name: "empty reader before status", + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = io.Copy(w, struct{ io.Reader }{strings.NewReader("")}) + w.WriteHeader(http.StatusNoContent) + }), + WantCode: http.StatusNoContent, + }, + { + Name: "failed reader before status", + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if _, err := io.Copy(w, iotest.ErrReader(errors.New("upstream failed"))); err != nil { + http.Error(w, err.Error(), http.StatusBadGateway) + } + }), + WantCode: http.StatusBadGateway, + WantWritten: int64(len("upstream failed\n")), + }, + { + Name: "nonempty reader before status", + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = io.Copy(w, struct{ io.Reader }{strings.NewReader("body")}) + w.WriteHeader(http.StatusBadGateway) + }), + WantCode: http.StatusOK, + WantWritten: 4, + }, { Name: "string writer", Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -112,6 +141,9 @@ func TestCaptureMetrics(t *testing.T) { } if err == nil { defer res.Body.Close() + if res.StatusCode != test.WantCode { + t.Errorf("test %d: response status=%d want=%d", i, res.StatusCode, test.WantCode) + } } m := <-ch if m.Code != test.WantCode {