aboutsummaryrefslogtreecommitdiff
path: root/src/net
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2024-07-26 13:23:09 -0700
committerGopher Robot <gobot@golang.org>2024-07-29 21:29:55 +0000
commit1ef6b2805ea1d78c082c7c55df39fc3d3942e4c9 (patch)
tree8a3a74bfd21e961d9d1d0a04e771cba002c181a0 /src/net
parentac51262592a20e16afec77163eff98be1d336f5c (diff)
downloadgo-1ef6b2805ea1d78c082c7c55df39fc3d3942e4c9.tar.xz
net/http: don't write HEAD response body in ResponseWriter.ReadFrom
Responses to HEAD requests don't have a body. The ResponseWriter automatically discards writes to the response body when responding to a HEAD request. ResponseWriter.ReadFrom was failing to discard writes under some circumstances; fix it to do so. Fixes #68609 Change-Id: I912f6b2b2a535df28ae37b875fcf15b10da1af2b Reviewed-on: https://go-review.googlesource.com/c/go/+/601475 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Auto-Submit: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/net')
-rw-r--r--src/net/http/serve_test.go30
-rw-r--r--src/net/http/server.go2
2 files changed, 30 insertions, 2 deletions
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index cc485d3b89..4d71eb0498 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -1510,7 +1510,7 @@ func testHeadResponses(t *testing.T, mode testMode) {
}
// Also exercise the ReaderFrom path
- _, err = io.Copy(w, strings.NewReader("789a"))
+ _, err = io.Copy(w, struct{ io.Reader }{strings.NewReader("789a")})
if err != nil {
t.Errorf("Copy(ResponseWriter, ...): %v", err)
}
@@ -1537,6 +1537,34 @@ func testHeadResponses(t *testing.T, mode testMode) {
}
}
+// Ensure ResponseWriter.ReadFrom doesn't write a body in response to a HEAD request.
+// https://go.dev/issue/68609
+func TestHeadReaderFrom(t *testing.T) { run(t, testHeadReaderFrom, []testMode{http1Mode}) }
+func testHeadReaderFrom(t *testing.T, mode testMode) {
+ // Body is large enough to exceed the content-sniffing length.
+ wantBody := strings.Repeat("a", 4096)
+ cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.(io.ReaderFrom).ReadFrom(strings.NewReader(wantBody))
+ }))
+ res, err := cst.c.Head(cst.ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ res, err = cst.c.Get(cst.ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ gotBody, err := io.ReadAll(res.Body)
+ res.Body.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(gotBody) != wantBody {
+ t.Errorf("got unexpected body len=%v, want %v", len(gotBody), len(wantBody))
+ }
+}
+
func TestTLSHandshakeTimeout(t *testing.T) {
run(t, testTLSHandshakeTimeout, []testMode{https1Mode, http2Mode})
}
diff --git a/src/net/http/server.go b/src/net/http/server.go
index 1ff72a0455..1eb0e50206 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -611,7 +611,7 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
w.cw.flush() // make sure Header is written; flush data to rwc
// Now that cw has been flushed, its chunking field is guaranteed initialized.
- if !w.cw.chunking && w.bodyAllowed() {
+ if !w.cw.chunking && w.bodyAllowed() && w.req.Method != "HEAD" {
n0, err := rf.ReadFrom(src)
n += n0
w.written += n0