Repository: caddyserver/caddy
File: modules/caddyhttp/app.go (Go)

Code before:
			_, h2cok := protocolsUnique["h2c"]
			_, h3ok := protocolsUnique["h3"]

			for portOffset := uint(0); portOffset < listenAddr.PortRangeSize(); portOffset++ {
				hostport := listenAddr.JoinHostPort(portOffset)

				// enable TLS if there is a policy and if this is not the HTTP port
				useTLS := len(srv.TLSConnPolicies) > 0 && int(listenAddr.StartPort+portOffset) != app.httpPort()

				// Can't serve HTTP/3 on the same socket as HTTP/1 and 2 because it uses
				// a different transport mechanism... which is fine, but the OS doesn't
				// differentiate between a SOCK_STREAM file and a SOCK_DGRAM file; they
				// are still one file on the system. So even though "unixpacket" and
				// "unixgram" are different network types just as "tcp" and "udp" are,
				// the OS will not let us use the same file as both STREAM and DGRAM.
				if h3ok && listenAddr.IsUnixNetwork() {
					app.logger.Warn("HTTP/3 disabled because Unix can't multiplex STREAM and DGRAM on same socket",
						zap.String("file", hostport))
					for i := range srv.Protocols {
						if srv.Protocols[i] == "h3" {
							srv.Protocols = append(srv.Protocols[:i], srv.Protocols[i+1:]...)
							break
						}
					}
					delete(protocolsUnique, "h3")
					h3ok = false
				}

				// enable HTTP/3 if configured
				if h3ok && useTLS {
					app.logger.Info("enabling HTTP/3 listener", zap.String("addr", hostport))
					if err := srv.serveHTTP3(listenAddr.At(portOffset), tlsCfg); err != nil {
						return err
					}
				}

				if h3ok && !useTLS {
					// Can only serve h3 with TLS enabled
					app.logger.Warn("HTTP/3 skipped because it requires TLS",
						zap.String("network", listenAddr.Network),
						zap.String("addr", hostport))
				}

				if h1ok || h2ok && useTLS || h2cok {
					// create the listener for this socket
					lnAny, err := listenAddr.Listen(app.ctx, portOffset, net.ListenConfig{KeepAlive: time.Duration(srv.KeepAliveInterval)})
					if err != nil {
						return fmt.Errorf("listening on %s: %v", listenAddr.At(portOffset), err)
					}
					ln, ok := lnAny.(net.Listener)
					if !ok {

Review comment (suggestion):
Shouldn't disable h3 completely, just skip this address is fine. As other addresses may be able to serve http3. A caddy http server can be be configured to listen both unix sockets and tcp/udp sockets through json.

Code after:
			_, h2cok := protocolsUnique["h2c"]
			_, h3ok := protocolsUnique["h3"]

			for portOffset := uint(0); portOffset < listenAddr.PortRangeSize(); portOffset++ {
				hostport := listenAddr.JoinHostPort(portOffset)

				// enable TLS if there is a policy and if this is not the HTTP port
				useTLS := len(srv.TLSConnPolicies) > 0 && int(listenAddr.StartPort+portOffset) != app.httpPort()

				if h1ok || h2ok && useTLS || h2cok {
					// create the listener for this socket
					lnAny, err := listenAddr.Listen(app.ctx, portOffset, net.ListenConfig{KeepAlive: time.Duration(srv.KeepAliveInterval)})
					if err != nil {
						return fmt.Errorf("listening on %s: %v", listenAddr.At(portOffset), err)
					}
					ln, ok := lnAny.(net.Listener)
					if !ok {
						return fmt.Errorf("network '%s' cannot handle HTTP/1 or HTTP/2 connections", listenAddr.Network)
					}

					// wrap listener before TLS (up to the TLS placeholder wrapper)
					var lnWrapperIdx int
					for i, lnWrapper := range srv.listenerWrappers {
						if _, ok := lnWrapper.(*tlsPlaceholderWrapper); ok {
							lnWrapperIdx = i + 1 // mark the next wrapper's spot
							break
						}
						ln = lnWrapper.WrapListener(ln)
					}

					if useTLS {
						// create TLS listener - this enables and terminates TLS
						ln = tls.NewListener(ln, tlsCfg)
					}

					// finish wrapping listener where we left off before TLS
					for i := lnWrapperIdx; i < len(srv.listenerWrappers); i++ {
						ln = srv.listenerWrappers[i].WrapListener(ln)
					}

					// handle http2 if use tls listener wrapper
					if h2ok {
						http2lnWrapper := &http2Listener{
							Listener: ln,
							server:   srv.server,
							h2server: h2server,
						}
						srv.h2listeners = append(srv.h2listeners, http2lnWrapper)
						ln = http2lnWrapper
					}