mirror of https://github.com/golang/go.git
net/http: add missing call to decConnsPerHost
A recent change to Transport.dialConnFor introduced an early return that skipped dialing. This path did not call decConnsPerHost, which can cause subsequent HTTP calls to hang if Transport.MaxConnsPerHost is set. Fixes: #65705 Change-Id: I157591114b02a3a66488d3ead7f1e6dbd374a41c Reviewed-on: https://go-review.googlesource.com/c/go/+/564036 Reviewed-by: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Damien Neil <dneil@google.com> Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
d42cd452dc
commit
098a87fb19
|
|
@ -1478,6 +1478,7 @@ func (t *Transport) dialConnFor(w *wantConn) {
|
|||
defer w.afterDial()
|
||||
ctx := w.getCtxForDial()
|
||||
if ctx == nil {
|
||||
t.decConnsPerHost(w.key)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -730,6 +730,56 @@ func testTransportMaxConnsPerHost(t *testing.T, mode testMode) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTransportMaxConnsPerHostDialCancellation(t *testing.T) {
|
||||
run(t, testTransportMaxConnsPerHostDialCancellation,
|
||||
testNotParallel, // because test uses SetPendingDialHooks
|
||||
[]testMode{http1Mode, https1Mode, http2Mode},
|
||||
)
|
||||
}
|
||||
|
||||
func testTransportMaxConnsPerHostDialCancellation(t *testing.T, mode testMode) {
|
||||
CondSkipHTTP2(t)
|
||||
|
||||
h := HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||
_, err := w.Write([]byte("foo"))
|
||||
if err != nil {
|
||||
t.Fatalf("Write: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
cst := newClientServerTest(t, mode, h)
|
||||
defer cst.close()
|
||||
ts := cst.ts
|
||||
c := ts.Client()
|
||||
tr := c.Transport.(*Transport)
|
||||
tr.MaxConnsPerHost = 1
|
||||
|
||||
// This request is cancelled when dial is queued, which preempts dialing.
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
SetPendingDialHooks(cancel, nil)
|
||||
defer SetPendingDialHooks(nil, nil)
|
||||
|
||||
req, _ := NewRequestWithContext(ctx, "GET", ts.URL, nil)
|
||||
_, err := c.Do(req)
|
||||
if !errors.Is(err, context.Canceled) {
|
||||
t.Errorf("expected error %v, got %v", context.Canceled, err)
|
||||
}
|
||||
|
||||
// This request should succeed.
|
||||
SetPendingDialHooks(nil, nil)
|
||||
req, _ = NewRequest("GET", ts.URL, nil)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("request failed: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
_, err = io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("read body failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransportRemovesDeadIdleConnections(t *testing.T) {
|
||||
run(t, testTransportRemovesDeadIdleConnections, []testMode{http1Mode})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue