Skip to content

net/http,x/net/http2: http2serverConn WriteTimeout cannot set negative values #65785

@eudore

Description

@eudore

Go version

go version go1.21.3 linux/amd64

Output of go env in your module/workspace:

GO111MODULE='off'
GOARCH='amd64'
GOBIN=''
GOCACHE='/root/.cache/go-build'
GOENV='/root/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/root/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/root/go:/data/web/golang'
GOPRIVATE=''
GOPROXY='https://goproxy.cn'
GOROOT='/usr/local/go1.21'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go1.21/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.3'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='0'
GOMOD=''
GOWORK=''
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 -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build3116255717=/tmp/go-build -gno-record-gcc-switches'

What did you do?

Set http.Server WriteTimeout to negative value.

Comment in http.Server: // A zero or negative value means there will be no timeout.

package main

import (
	"fmt"
	"net"
	"net/http"
	"time"
)

func main() {
	srv := &http.Server{
		WriteTimeout: -1 * time.Second,
	}

	ln, err := net.Listen("tcp", ":8088")
	if err != nil {
		panic(err)
	}
	go srv.Serve(ln)

	ln, err = net.Listen("tcp", ":8089")
	if err != nil {
		panic(err)
	}
	go runClient()

	err = srv.ServeTLS(ln, "/etc/nginx/openssl/eudore.cn/www.eudore.cn.pem", "/etc/nginx/openssl/eudore.cn/www.eudore.cn.key")
	if err != nil {
		panic(err)
	}
}

func runClient() {
	time.Sleep(time.Second)
	fmt.Println(http.Get("http://www.eudore.cn:8088"))
	fmt.Println(http.Get("https://www.eudore.cn:8089"))
}

What did you see happen?

Using golang h2 client request shows error.

&{404 Not Found 404 HTTP/1.1 1 1 map[Content-Length:[19] Content-Type:[text/plain; charset=utf-8] Date:[Mon, 19 Feb 2024 07:08:39 GMT] X-Content-Type-Options:[nosniff]] 0xc0001820c0 19 [] false false map[] 0xc0000b6360 <nil>} <nil>
<nil> Get "https://www.eudore.cn:8089": stream error: stream ID 1; INTERNAL_ERROR; received from peer

If you use the current version of chrome to access, ERR_HTTP2_PROTOCOL_ERROR is displayed.

The webpage at https://www.eudore.cn:8089/ might be temporarily down or it may have moved permanently to a new web address.
ERR_HTTP2_PROTOCOL_ERROR

What did you expect to see?

h2 server handles negative WriteTimeouts normally.

&{404 Not Found 404 HTTP/1.1 1 1 map[Content-Length:[19] Content-Type:[text/plain; charset=utf-8] Date:[Mon, 19 Feb 2024 07:08:22 GMT] X-Content-Type-Options:[nosniff]] 0xc00007c600 19 [] false false map[] 0xc00008c360 <nil>} <nil>
&{404 Not Found 404 HTTP/2.0 2 0 map[Content-Length:[19] Content-Type:[text/plain; charset=utf-8] Date:[Mon, 19 Feb 2024 07:08:22 GMT] X-Content-Type-Options:[nosniff]] {0xc0002b2180} 19 [] false false map[] 0xc00008c7e0 0xc0000844d0} <nil>

In the current go version, http.Server and http.http2serverConn set WriteTimeout judgment conditions differently.

func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
	...
	if d := c.server.WriteTimeout; d > 0 {
		defer func() {
			c.rwc.SetWriteDeadline(time.Now().Add(d))
		}()
	}
	...
}

func (sc *http2serverConn) newStream(id, pusherID uint32, state http2streamState) *http2stream {
	...
	if sc.hs.WriteTimeout != 0 {
		st.writeDeadline = time.AfterFunc(sc.hs.WriteTimeout, st.onWriteTimeout)
	}
	...
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    FixPendingIssues that have a fix which has not yet been reviewed or submitted.FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions