Closed
Description
What version of Go are you using (go version
)?
$ go version go version go1.17 linux/amd64
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GO111MODULE="on" GOARCH="amd64" GOBIN="" GOCACHE="/home/ubuntu/.cache/go-build" GOENV="/home/ubuntu/.config/go/env" GOEXE="" GOEXPERIMENT="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GOMODCACHE="/home/ubuntu/dev/gopath/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/home/ubuntu/dev/gopath" GOPRIVATE="" GOPROXY="direct" GOROOT="/home/ubuntu/dev/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/home/ubuntu/dev/go/pkg/tool/linux_amd64" GOVCS="" GOVERSION="go1.17" GCCGO="gccgo" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="/dev/null" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build2048112507=/tmp/go-build -gno-record-gcc-switches"
What did you do?
Here are the code that can reproduce it:
// server.go
package main
import (
"io"
"net/http"
_ "net/http/pprof"
"time"
)
func main() {
mux := &http.ServeMux{}
mux.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) {
data, _ := io.ReadAll(r.Body)
w.Write(data)
})
server := http.Server{
Addr: "localhost:8080",
Handler: mux,
// Set IdleTimeout to 3s
IdleTimeout: 3 * time.Second,
}
server.ListenAndServe()
}
// client.go
package main
import (
"log"
"net"
"time"
)
func main() {
go func() {
for i := 0; true; i++ {
// Keep printing alive until the conn is closed and the process exit
log.Printf("alive %vs", i)
time.Sleep(time.Second)
}
}()
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
panic(err)
}
// step 1: Send the first request
reqData := []byte("POST /echo HTTP/1.1\r\nHost: localhost:8080\r\nContent-Length: 5\r\nAccept-Encoding: gzip\r\n\r\nhello")
_, err = conn.Write(reqData)
if err != nil {
panic(err)
}
// step 2: Recv the first response
resData := make([]byte, 1024)
n, err := conn.Read(resData)
if err != nil {
panic(err)
}
log.Printf("resData: \n-----\n%v\n-----\nerror: %v", string(resData[:n]), err)
// step 3: Send 4 bytes to server, no longer send the left data of a full request
_, err = conn.Write(reqData[:4])
if err != nil {
log.Fatal(err)
}
// step 4: Read and wait the server close the conn.
// The server will not close the conn and will block here
_, err = conn.Read(resData)
if err != nil {
log.Fatal(err)
}
}
# client output
2022/03/11 21:39:44 resData:
-----
HTTP/1.1 200 OK
Date: Fri, 11 Mar 2022 13:39:44 GMT
Content-Length: 5
Content-Type: text/plain; charset=utf-8
hello
-----
error: <nil>
2022/03/11 21:39:44 alive 1s
2022/03/11 21:39:45 alive 2s
2022/03/11 21:39:46 alive 3s
...
2022/03/11 21:41:44 alive 120s
...
...
What did you expect to see?
The server should close the client conn when the client didn't send all the request data after Server.IdleTimeout
What did you see instead?
The server didn't close the clien conn