Skip to content

net/http/httptest: Server uses ipv4 instead of using both Ipv4 and Ipv6 #71178

@bdollma-te

Description

@bdollma-te

Go version

go version go1.21.0 linux/amd64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN='/auto/srg-sce-swinfra-usr/emb/users/bdollma/sdflow/scripts/../bin'
GOCACHE='/auto/srg-sce-swinfra-usr/emb/users/bdollma/go/cache'
GOENV='/users/bdollma/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/auto/srg-sce-swinfra-usr/emb/users/bdollma/sdflow/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/auto/srg-sce-swinfra-usr/emb/users/bdollma/sdflow/scripts/..'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/auto/srg-sce-swinfra-usr/emb/users/bdollma/go1.21.0'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/auto/srg-sce-swinfra-usr/emb/users/bdollma/go1.21.0/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.0'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/dev/null'
GOWORK='/auto/srg-sce-swinfra-usr/emb/users/bdollma/sdflow/go.work'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1206231536=/tmp/go-build -gno-record-gcc-switches'

What did you do?

Create a httptest.Server using the NewServer.

func TestIssue(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	}))
	defer srv.Close()

	u, err := url.Parse(srv.URL)
	require.NoError(t, err)
	port, err := strconv.Atoi(u.Port())
	require.NoError(t, err)
	url := fmt.Sprintf("http://localhost:%d", port)

	client := http.Client{}
	req, err := http.NewRequest(http.MethodPost, url, http.NoBody)
	require.NoError(t, err)
	req.Close = true
	resp, err := client.Do(req)
	require.NoError(t, err)
	require.Equal(t, http.StatusOK, resp.StatusCode)
}

Run the test:

go test -v . -run TestIssue -count 10000 -failfast
    http_server_test.go:280: 
                Error Trace:    ...
                Error:          Received unexpected error:
                                Post "http://localhost:44269": EOF
                Test:           TestIssue

What did you see happen?

After drilling down, the listener created for httptest.Server is IPv4 only:

l, err := net.Listen("tcp", "127.0.0.1:0")

and uses 127.0.0.1:0.

The test fails because at some point the client starts using IPv6. The server simply doesn't respond.

Screenshot 2025-01-08 at 17 18 25

What did you expect to see?

At least a better error. Simply returning EOF doesn't remotely help pinpoint the error.
You can argue that I should have used srv.URL instead of parsing the port and using localhost:port. However, in real world scenarios the code expects a port and runs a DNS lookup.

Even better, why not listen at both ipv4 and ipv6 by default?

l, err := net.Listen("tcp", ":0")

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