diff --git a/http2/transport.go b/http2/transport.go index 94b397c69..f26356b9c 100644 --- a/http2/transport.go +++ b/http2/transport.go @@ -2210,6 +2210,13 @@ func (rl *clientConnReadLoop) cleanup() { } cc.cond.Broadcast() cc.mu.Unlock() + + if !cc.seenSettings { + // If we have a pending request that wants extended CONNECT, + // let it continue and fail with the connection error. + cc.extendedConnectAllowed = true + close(cc.seenSettingsChan) + } } // countReadFrameError calls Transport.CountError with a string @@ -2302,9 +2309,6 @@ func (rl *clientConnReadLoop) run() error { if VerboseLogs { cc.vlogf("http2: Transport conn %p received error from processing frame %v: %v", cc, summarizeFrame(f), err) } - if !cc.seenSettings { - close(cc.seenSettingsChan) - } return err } } diff --git a/http2/transport_test.go b/http2/transport_test.go index d1d27f8f9..1eeb76e06 100644 --- a/http2/transport_test.go +++ b/http2/transport_test.go @@ -5914,3 +5914,24 @@ func TestExtendedConnectClientWithoutServerSupport(t *testing.T) { t.Fatalf("expected error errExtendedConnectNotSupported, got: %v", err) } } + +// Issue #70658: Make sure extended CONNECT requests don't get stuck if a +// connection fails early in its lifetime. +func TestExtendedConnectReadFrameError(t *testing.T) { + tc := newTestClientConn(t) + tc.wantFrameType(FrameSettings) + tc.wantFrameType(FrameWindowUpdate) + + req, _ := http.NewRequest("CONNECT", "https://dummy.tld/", nil) + req.Header.Set(":protocol", "extended-connect") + rt := tc.roundTrip(req) + tc.wantIdle() // waiting for SETTINGS response + + tc.closeWrite() // connection breaks without sending SETTINGS + if !rt.done() { + t.Fatalf("after connection closed: RoundTrip still running; want done") + } + if rt.err() == nil { + t.Fatalf("after connection closed: RoundTrip succeeded; want error") + } +}