Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/http: HTTP requests with InsecureSkipVerify transport don't close TCP connections #16267

knadh opened this issue Jul 5, 2016 · 1 comment


Copy link

@knadh knadh commented Jul 5, 2016

  1. What version of Go are you using (go version)?
    go version go1.6.2 linux/amd64
  2. What operating system and processor architecture are you using (go env)?
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0"
  1. What did you do?

Run the following program. It creates an HTTP server on :8000 and spawns a goroutine that sends GET requests to the server every 1 second. The server writes nothing in the response body; body-length = 0. The client makes GET requests and does a body.Close() without reading the body. Note that the transport has InsecureSkipVerify.

package main

import (

func Server(w http.ResponseWriter, req *http.Request) {
    // If a response is written, the issue isn't triggered.
    // io.WriteString(w, "hello, world!\n")

func Client(url string) {
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {

    // This transport is what's causing unclosed connections.
    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    hc := &http.Client{Timeout: 2 * time.Second, Transport: tr}

    resp, err := hc.Do(req)
    if err != nil {
    defer resp.Body.Close()

func main() {
    // Wait a bit and launch one client every second.
    // On the terminal, run `ss | grep :8000` to see
    // ESTABLISHED connections grow with every request.

    go func() {
        time.Sleep(1 * time.Second)

        n := 0
        for {
            fmt.Println("Request", n)
            n += 1

            time.Sleep(1 * time.Second)

    http.HandleFunc("/", Server)
    log.Fatal(http.ListenAndServe(":8000", nil))
  1. What did you expect to see?
    Every request the client makes should get a 200 response from the server and immediately close the connection.
  2. What did you see instead?
    The client keeps making requests and gets 200 back, but the underlying TCP connection is never closed. It's stuck in the ESTABLISHED state perpetually.

Check the open connections by running ss | grep :8000 every few seconds. They keep growing. netstat n | grep :8000 also shows TIME_WAIT connections.

  • Writing a response in Server() solves the issue.
  • Removing InsecureSkipVerify solves the issue.
@knadh knadh changed the title net/http: HTTP requests with InsecureSkipVerify transport doesn't close connections net/http: HTTP requests with InsecureSkipVerify transport don't close TCP connections Jul 5, 2016
Copy link

@bradfitz bradfitz commented Jul 5, 2016

This has nothing to do with InsecureSkipVerify.

You're leaking Transports which are holding TCP connections.

See the documentation under :

By default, Transport caches connections for future re-use. This may leave many open connections when accessing many hosts. This behavior can be managed using Transport's CloseIdleConnections method and the MaxIdleConnsPerHost and DisableKeepAlives fields.

Transports should be reused instead of created as needed. Transports are safe for concurrent use by multiple goroutines.

Don't create a Transport for every request.

@bradfitz bradfitz closed this Jul 5, 2016
@golang golang locked and limited conversation to collaborators Jul 5, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants