Skip to content

zombie connection and goroutine leaked using router.Run #3077

@lesismal

Description

@lesismal

Related or same issue: golang/go#51614

Slow connection attack, the device of the client power off, wifi changed, entering an elevator may cause that the client will never send TCP.FIN to the server, then the conn will never be closed and the goroutine serving the conn will never exit.

Description

How to reproduce

package main

import (
	"log"
	"net"
	"net/http"
	_ "net/http/pprof"
	"time"

	"github.com/gin-gonic/gin"
)

func client() {
	go func() {
		for i := 1; true; i++ {
			// Keep printing alive until the conn is closed and the process exit
			time.Sleep(time.Second)
			log.Printf("alive %vs", i)
		}
	}()

	conn, err := net.Dial("tcp", "localhost:8080")
	if err != nil {
		panic(err)
	}

	// step 1: Send the first request
	reqData := []byte("GET /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: 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)
	}
}

func main() {
	router := gin.New()
	router.GET("/echo", func(c *gin.Context) {
		c.String(http.StatusOK, "hello world")
	})

	time.AfterFunc(time.Second, client)
	router.Run("localhost:8080")
}

Expectations

The server should close the client conn when the client no longer send request data to the server

Actual result

  • The server will never close the clien conn, then the conn and the goroutine serving the conn would be leaked
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /echo                     --> main.main.func1 (1 handlers)
[GIN-debug] Listening and serving HTTP on localhost:8080
2022/03/12 19:10:17 resData:
-----
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Date: Sat, 12 Mar 2022 11:10:17 GMT
Content-Length: 11

hello world
-----
error: <nil>
2022/03/12 19:10:18 alive 1s
2022/03/12 19:10:19 alive 2s
2022/03/12 19:10:20 alive 3s
...
...
...

Environment

  • go version: 1.17
  • gin version (or commit ref): latest
  • operating system: win/mac/linux...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions