diff options
| author | Nicholas S. Husin <nsh@golang.org> | 2026-03-09 17:02:27 -0400 |
|---|---|---|
| committer | Nicholas Husin <nsh@golang.org> | 2026-03-11 10:12:36 -0700 |
| commit | 96d6d38872a56eba26cd2e3dbd65bab138f9c599 (patch) | |
| tree | aca7d3a7d6ebc923ed96fdd4da1ab8b18620992e /src/net/http | |
| parent | e30e65f7a8bda0351d9def5a6bc91471bddafd3d (diff) | |
| download | go-96d6d38872a56eba26cd2e3dbd65bab138f9c599.tar.xz | |
net/http: add pluggable HTTP/3 support for closing idle connections
This CL defines the closeIdleConectionser interface, allowing us to call
a CloseIdleConnections method that a pluggable HTTP/3 transport might
implement.
Concretely, this allows an HTTP/3 transport implementation to clean up
resources such as an open UDP socket that is no longer needed,
preventing resources from lingering around indefinitely until the entire
program exits.
For #77440
Change-Id: I7216caee58954c3651f96a56dbf27ec74c539ad3
Reviewed-on: https://go-review.googlesource.com/c/go/+/753161
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Diffstat (limited to 'src/net/http')
| -rw-r--r-- | src/net/http/transport.go | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/src/net/http/transport.go b/src/net/http/transport.go index efc3838154..32bbb04759 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -388,9 +388,8 @@ type dialClientConner interface { // If HTTP/3 proxies are not supported, DialClientConn should return // an error wrapping [errors.ErrUnsupported]. // - // The RoundTripper returned by DialClientConn may implement - // any of the following methods to support the [ClientConn] - // method of the same name: + // The RoundTripper returned by DialClientConn must also implement the + // following methods to support [ClientConn] methods of the same name: // Close() error // Err() error // Reserve() error @@ -411,6 +410,16 @@ type dialClientConner interface { DialClientConn(ctx context.Context, address string, proxy *url.URL, internalStateHook func()) (RoundTripper, error) } +type closeIdleConnectionser interface { + // CloseIdleConnections is called by Transport.CloseIdleConnections. + // + // The transport will close idle connections created with DialClientConn + // before calling this method. The HTTP/3 transport should not attempt to + // close idle connections, but may clean up shared resources such as UDP + // sockets if no connections remain. + CloseIdleConnections() +} + // h2Transport is the interface we expect to be able to call from // net/http against an *http2.Transport that's either bundled into // h2_bundle.go or supplied by the user via x/net/http2. @@ -956,6 +965,9 @@ func (t *Transport) CloseIdleConnections() { if t2 := t.h2transport; t2 != nil { t2.CloseIdleConnections() } + if cc, ok := t.h3transport.(closeIdleConnectionser); ok { + cc.CloseIdleConnections() + } } // prepareTransportCancel sets up state to convert Transport.CancelRequest into context cancelation. @@ -3088,11 +3100,16 @@ func (pc *persistConn) closeLocked(err error) { pc.t.decConnsPerHost(pc.cacheKey) // Close HTTP/1 (pc.alt == nil) connection. // HTTP/2 closes its connection itself. + // Close HTTP/3 connection if it implements io.Closer. if pc.alt == nil { if err != errCallerOwnsConn { pc.conn.Close() } close(pc.closech) + } else { + if cc, ok := pc.alt.(io.Closer); ok { + cc.Close() + } } } pc.mutateHeaderFunc = nil |
