From 6b955748417be7392ea2b48aded5ca65f40f40f9 Mon Sep 17 00:00:00 2001 From: WeidiDeng Date: Fri, 29 Mar 2024 10:02:55 +0800 Subject: [PATCH 1/3] close quic connections when server closes --- modules/caddyhttp/server.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index ea748bc12e2..114675b614c 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -567,13 +567,28 @@ func (s *Server) serveHTTP3(addr caddy.NetworkAddress, tlsCfg *tls.Config) error // create HTTP/3 server if not done already if s.h3server == nil { + // Currently when closing a http3.Server, only listeners are closed. But caddy reuses these listeners + // if possible, requests are still read and handled by the old handler. Close these connections manually. + // see issue: https://github.com/caddyserver/caddy/issues/6195 s.h3server = &http3.Server{ - Handler: s, + Handler: http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + select { + case <-s.ctx.Done(): + if quicConn, ok := request.Context().Value(quicConnCtxKey).(quic.Connection); ok { + quicConn.CloseWithError(quic.ApplicationErrorCode(http3.ErrCodeRequestRejected), "") + } + default: + s.ServeHTTP(writer, request) + } + }), TLSConfig: tlsCfg, MaxHeaderBytes: s.MaxHeaderBytes, // TODO: remove this config when draft versions are no longer supported (we have no need to support drafts) QuicConfig: &quic.Config{ - Versions: []quic.VersionNumber{quic.Version1, quic.Version2}, + Versions: []quic.Version{quic.Version1, quic.Version2}, + }, + ConnContext: func(ctx context.Context, c quic.Connection) context.Context { + return context.WithValue(ctx, quicConnCtxKey, c) }, } } @@ -992,6 +1007,10 @@ const ( // For referencing underlying net.Conn ConnCtxKey caddy.CtxKey = "conn" + // For referencing underlying quic.Connection + // TODO: export if needed later + quicConnCtxKey caddy.CtxKey = "quic_conn" + // For tracking whether the client is a trusted proxy TrustedProxyVarKey string = "trusted_proxy" From d794ab45e24b309f5008b07117e35f78da767425 Mon Sep 17 00:00:00 2001 From: WeidiDeng Date: Fri, 29 Mar 2024 10:08:43 +0800 Subject: [PATCH 2/3] fix lint --- modules/caddyhttp/server.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index 114675b614c..ad807d52087 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -575,6 +575,7 @@ func (s *Server) serveHTTP3(addr caddy.NetworkAddress, tlsCfg *tls.Config) error select { case <-s.ctx.Done(): if quicConn, ok := request.Context().Value(quicConnCtxKey).(quic.Connection); ok { + //nolint:errcheck quicConn.CloseWithError(quic.ApplicationErrorCode(http3.ErrCodeRequestRejected), "") } default: From 6f351a1c59d66e18091103e833605d664ebcf2d2 Mon Sep 17 00:00:00 2001 From: WeidiDeng Date: Fri, 29 Mar 2024 14:43:31 +0800 Subject: [PATCH 3/3] add comment about CloseGracefully --- modules/caddyhttp/server.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index ad807d52087..c7e5a5f6132 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -567,10 +567,12 @@ func (s *Server) serveHTTP3(addr caddy.NetworkAddress, tlsCfg *tls.Config) error // create HTTP/3 server if not done already if s.h3server == nil { - // Currently when closing a http3.Server, only listeners are closed. But caddy reuses these listeners - // if possible, requests are still read and handled by the old handler. Close these connections manually. - // see issue: https://github.com/caddyserver/caddy/issues/6195 s.h3server = &http3.Server{ + // Currently when closing a http3.Server, only listeners are closed. But caddy reuses these listeners + // if possible, requests are still read and handled by the old handler. Close these connections manually. + // see issue: https://github.com/caddyserver/caddy/issues/6195 + // Will interrupt ongoing requests. + // TODO: remove the handler wrap after http3.Server.CloseGracefully is implemented, see App.Stop Handler: http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { select { case <-s.ctx.Done():