Description
What version of Go are you using (go version
)?
$ go version go version go1.20.2 darwin/arm64
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GO111MODULE="on" GOARCH="arm64" GOHOSTARCH="arm64" GOHOSTOS="darwin" GOOS="darwin" GOPROXY="direct" GOROOT="/opt/homebrew/Cellar/go/1.20.2/libexec" GOSUMDB="sum.golang.org" GOTOOLDIR="/opt/homebrew/Cellar/go/1.20.2/libexec/pkg/tool/darwin_arm64" GOVERSION="go1.20.2" GCCGO="gccgo" AR="ar" CC="cc" CXX="c++" CGO_ENABLED="1" CGO_CFLAGS="-O2 -g" CGO_CXXFLAGS="-O2 -g" CGO_FFLAGS="-O2 -g" CGO_LDFLAGS="-O2 -g" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/g4/47vwdw1s65929qw7smyq1vlswhhzgj/T/go-build4150723989=/tmp/go-build -gno-record-gcc-switches -fno-common"
What did you do?
Create an HTTP2 transport with AllowHTTP = true, and try to send a request using it with req.Close = true. This will hang until the internal retry mechanism in the HTTP2 roundtrip ends after exponential backoff.
https://go.dev/play/p/KhmQcQB0PPD
If you remove req.Close = true, in my contrived example you get unexpected EOF, but the point is no timeout, because its not retrying aimlessly.
What did you expect to see?
I would expect the transport to understand that AllowHTTP=true setting nextStreamID to 3 in the newClientConn() function does not mean it should be considered "not usable" before it ever makes a request.
What did you see instead?
2009/11/10 23:00:00 Starting server...
2009/11/10 23:00:00 Sending request...
<time passes because of retry backoff>
http2: client conn not usable
The issue is because of this line that sets nextStreamID to 3 before a request is ever made, and then this line that interprets a nextStreamID higher than 1 as having been "used".
I'm not sure my use case for this is exactly "up to standard" but it seems like the behavior is unintentional - the connection should be usable once even if AllowHTTP was set on its creation, and at least it shouldn't retry exponentially when there's no way it could get a different outcome in the next iteration.
Thanks for reading!