Go version
go version go1.24.3 darwin/arm64
Output of go env
in your module/workspace:
AR='ar'
CC='clang'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='clang++'
GCCGO='gccgo'
GO111MODULE=''
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/Users/REDACTED/Library/Caches/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/Users/REDACTED/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/3m/m4kn6p6510zbvxpx5nyzpbfr0000gn/T/go-build1423855236=/tmp/go-build -gno-record-gcc-switches -fno-common'
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMOD='REDACTED'
GOMODCACHE='/Users/REDACTED/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/REDACTED/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/REDACTED/Library/Application Support/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.24.3'
GOWORK=''
PKG_CONFIG='pkg-config'
What did you do?
func Test_HttpEcho(t *testing.T) {
httpServer := &http.Server{
Addr: ":5555",
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := io.Copy(w, r.Body)
if err != nil {
t.Fatal(err)
}
r.Body.Close()
}),
}
go httpServer.ListenAndServe()
defer httpServer.Close()
http.Post("http://127.0.0.1:5555/", "", strings.NewReader(strings.Repeat("X", 1<<10)))
}
Results in http: invalid Read on closed Body
What did you see happen?
io.Copy
returned an error http: invalid Read on closed Body
w.w.Flush()
in /usr/local/go/src/net/http/server.go line 610 is closing the r.Body
after sniffing the first 512 bytes. The closing itself happens at /usr/local/go/src/net/http/server.go line 1471 err = w.reqBody.Close()
.
What did you expect to see?
I did not expect an error from io.Copy
.
The following alternative code does NOT error out and works as expected.
func Test_HttpEcho(t *testing.T) {
httpServer := &http.Server{
Addr: ":5555",
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
t.Fatal(err)
}
_, err = w.Write(body)
if err != nil {
t.Fatal(err)
}
r.Body.Close()
}),
}
go httpServer.ListenAndServe()
defer httpServer.Close()
http.Post("http://127.0.0.1:5555/", "", strings.NewReader(strings.Repeat("X", 1<<10)))
}
Comment From: seankhliao
From http.ResponseWriter.Write:
// Depending on the HTTP protocol version and the client, calling // Write or WriteHeader may prevent future reads on the // Request.Body. For HTTP/1.x requests, handlers should read any // needed request body data before writing the response.
See https://pkg.go.dev/net/http#ResponseController.EnableFullDuplex
Unlike many projects, the Go project does not use GitHub Issues for general discussion or asking questions. GitHub Issues are used for tracking bugs and proposals only.
For questions please refer to https://github.com/golang/go/wiki/Questions