Go version

go version go1.22.0 windows/amd64

Output of go env in your module/workspace:

set GO111MODULE=
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\user\AppData\Local\go-build
set GOENV=C:\Users\user\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\user\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\user\go
set GOPRIVATE=
set GOPROXY=https://goproxy.io,direct
set GOROOT=C:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLCHAIN=auto
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.22.0
set GCCGO=gccgo
set GOAMD64=v1
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=0
set GOMOD=NUL
set GOWORK=
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\user\AppData\Local\Temp\go-build1134552419=/tmp/go-build -gno-record-gcc-switches

What did you do?

        test, err := httputil.DumpResponse(resp, true)
        resp.Body.Close()
        test, err = io.ReadAll(resp.Body)
        fmt.Println(string(test), err)

What did you see happen?

test is still readable.

What did you expect to see?

the resp.Body is closed.

https://github.com/golang/go/blob/97bc577812592c2bc40bd1f2bc0d78c5d8281ff6/src/net/http/httputil/dump.go#L322 this line return both new and old resp are nopcloser

should I open a PR?

Comment From: gabyhelp

Similar Issues

  • https://github.com/golang/go/issues/39290
  • https://github.com/golang/go/issues/54616
  • https://github.com/golang/go/issues/65009
  • https://github.com/golang/go/issues/19499
  • https://github.com/golang/go/issues/34295

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Comment From: prattmic

cc @neild

Comment From: neild

I'm not certain if I understand correctly, but I think you're saying that closing the body should cause further reads to return an error.

httputil.Dump* just replace the body with a bytes.Reader wrapped in an io.NopCloser. Is there really a need for anything more complicated?

Comment From: NewUserHa

according to the document, the response.Body should be closed, even the new body is just a bytes.Reader wrapped in an io.NopCloser, it may not cause real issue, but it should keep the same behavior as the real response.Body

https://go.dev/src/net/http/response.go
    // The http Client and Transport guarantee that Body is always
    // non-nil, even on responses without a body or responses with
    // a zero-length body. It is the caller's responsibility to
    // close Body. The default HTTP client's Transport may not
    // reuse HTTP/1.x "keep-alive" TCP connections if the Body is
    // not read to completion and closed.

Comment From: rsc

There is no requirement about how exactly a body implementation responds to misuse such as Read after Close. It is perfectly valid to use io.NopCloser, which implements Close as a no-op, in which case Read after Close does work. You cannot rely on an error from Read after Close.