aboutsummaryrefslogtreecommitdiff
path: root/src/net/http
diff options
context:
space:
mode:
authorNicholas S. Husin <nsh@golang.org>2026-03-09 17:02:27 -0400
committerNicholas Husin <nsh@golang.org>2026-03-11 10:12:36 -0700
commit96d6d38872a56eba26cd2e3dbd65bab138f9c599 (patch)
treeaca7d3a7d6ebc923ed96fdd4da1ab8b18620992e /src/net/http
parente30e65f7a8bda0351d9def5a6bc91471bddafd3d (diff)
downloadgo-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.go23
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