Skip to content

net/http: "use of closed network connection" error when reading 1MB or so #21760

Closed
@kevinburke

Description

@kevinburke

Originally reported as ipfs/kubo#3855 - my thanks to @timthelion, @whyrusleeping and others for helping debug.

What version of Go are you using (go version)?

Tip go version devel +812b34efae Mon Sep 4 00:07:33 2017 +0000 darwin/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/kevin"
GORACE=""
GOROOT="/Users/kevin/go"
GOTOOLDIR="/Users/kevin/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/sf/fsn3_vgd0n98r0jb86bgp83r0000gn/T/go-build607690397=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"

What did you do?

Here's a test case exposing the error.

type failReader struct {
	tot   int64
	limit int64
}

func (fr *failReader) Read(b []byte) (int, error) {
	fr.tot += int64(len(b))
	if fr.tot > fr.limit {
		return 0, fmt.Errorf("look at my cool error")
	}

	return len(b), nil
}

func TestConnectionCloseManyFiles(t *testing.T) {
	mux := NewServeMux()
	mux.HandleFunc("/", func(w ResponseWriter, r *Request) {
		buf := make([]byte, 4096)
		var tot int64
		_, err := w.Write([]byte("foobar"))
		if err != nil {
			t.Fatal(err)
		}
		w.(Flusher).Flush()
		for {
			n, err := r.Body.Read(buf)
			if err != nil {
				fmt.Println("read error: ", err)
				fmt.Println("total bytes: ", tot)
				break
			}

			//fmt.Println("total so far: ", tot)
			tot += int64(n)
		}
		_, err = w.Write([]byte("foobar"))
		if err != nil {
			t.Fatal(err)
		}
	})
	s := httptest.NewServer(mux)

	r := &failReader{
		limit: 1*1000*1000,
	}
	req, err := NewRequest("POST", s.URL, r)
	if err != nil {
		panic(err)
	}

	resp, err := DefaultClient.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()

	buf := new(bytes.Buffer)
	_, err = io.Copy(buf, resp.Body)
	if err != nil {
		t.Fatal(err)
	}
	if got := buf.String(); got != "foobar" {
		t.Errorf("Write: got %s, want %s", got, "foobar")
	}
}

You can tweak the numbers as you see fit; it takes about a million bytes read to trigger the error.

What did you expect to see?

I expect to see something like

	client_test.go:1836: Post http://127.0.0.1:50390: look at my cool error

What did you see instead?

This odd error:

client_test.go:1843: read tcp 127.0.0.1:50389->127.0.0.1:50388: use of closed network connection

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions