You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2025/07/12 11:59:51 UTC

(dubbo-go) branch develop updated: Feat: Add Experimental Triple HTTP/3 Support (#2916)

This is an automated email from the ASF dual-hosted git repository.

alexstocks pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git


The following commit(s) were added to refs/heads/develop by this push:
     new 43c8bd03a Feat: Add Experimental Triple HTTP/3 Support (#2916)
43c8bd03a is described below

commit 43c8bd03adb00ba1adf978d7625c02a047a65929
Author: marsevilspirit <ma...@gmail.com>
AuthorDate: Sat Jul 12 19:59:45 2025 +0800

    Feat: Add Experimental Triple HTTP/3 Support (#2916)
    
    * start triple http3 server successfully!
    
    * add http3 config for triple protocol
    
    * rename URL to url
    
    * fix v1.33.0 of google.golang.org/protobuf Fails to Compile
    ref: https://github.com/protocolbuffers/protobuf/issues/16163
    
    * triple http3 client start successfully!
    
    * add some comments
    
    * update triple server run logic
    
    * optimize http type
    
    * make triple http3 support keepalive option
    
    * add http2 keepalive config with tls
    
    * rename genKeepAliveOptions
    
    * add some todo
    
    * opitmize tlsConf params
    
    * fix http protocol bug
    
    * rename callProtocol
    
    * add some comments about http3 config
    
    * make panic when triple http3 server's TLS config is nil.
    
    * fix typo
    
    * opitmize config code
    
    * add experimental warning for http3 api
    
    * add some todo
    
    * support instance and yaml start with http3
    
    * enable http3 gracefulstop
    
    * opitmize callprotocol usage
    
    * rename ProtocolClientConfig to ClientProtocolConfig
    
    * replace panic with return error
    
    * optimize logger output
    
    * optimize parser error
    
    * add some comments
    
    * add config unit tests
    
    * Use a WaitGroup to manage the concurrent shutdown of goroutines effectively.
    
    * fix typo and add config unit test
    
    * use switch to handle error
---
 client/options.go                                  |   2 +-
 common/constant/key.go                             |   2 +-
 compat.go                                          | 157 +++++++++++++++++----
 .../client_protocol_config.go                      |  30 +---
 config/{triple_config.go => http3_config.go}       |  20 ++-
 config/reference_config.go                         |  44 +++---
 config/triple_config.go                            |  12 +-
 ..._client_config.go => client_protocol_config.go} |  16 +--
 global/config_test.go                              |  21 +++
 .../{protocol_client_config.go => http3_config.go} |  42 +++---
 global/reference_config.go                         |  16 ++-
 global/triple_config.go                            |  33 ++++-
 go.mod                                             |  34 +++--
 go.sum                                             |  74 +++++-----
 protocol/options.go                                |   4 +-
 protocol/triple/client.go                          |  86 ++++++++---
 protocol/triple/options.go                         |  13 ++
 protocol/triple/server.go                          |  70 +++++----
 protocol/triple/triple_protocol/server.go          | 156 ++++++++++++++++++--
 19 files changed, 592 insertions(+), 240 deletions(-)

diff --git a/client/options.go b/client/options.go
index 051558043..9d0b47991 100644
--- a/client/options.go
+++ b/client/options.go
@@ -856,7 +856,7 @@ func WithClientProtocol(opts ...protocol.ClientOption) ClientOption {
 
 	return func(srvOpts *ClientOptions) {
 		if srvOpts.overallReference.ProtocolClientConfig == nil {
-			srvOpts.overallReference.ProtocolClientConfig = new(global.ProtocolClientConfig)
+			srvOpts.overallReference.ProtocolClientConfig = new(global.ClientProtocolConfig)
 		}
 		srvOpts.overallReference.ProtocolClientConfig = proOpts.ProtocolClient
 	}
diff --git a/common/constant/key.go b/common/constant/key.go
index 43ace78c7..fdc9cc576 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -158,9 +158,9 @@ const (
 	CallClientStream                   = "client-stream"
 	CallServerStream                   = "server-stream"
 	CallBidiStream                     = "bidi-stream"
-	CallHTTPTypeKey                    = "call-http-type"
 	CallHTTP                           = "http"
 	CallHTTP2                          = "http2"
+	CallHTTP3                          = "http3"
 	ServiceInfoKey                     = "service-info"
 	RpcServiceKey                      = "rpc-service"
 	ClientInfoKey                      = "client-info"
diff --git a/compat.go b/compat.go
index 5c622c369..a46dbf851 100644
--- a/compat.go
+++ b/compat.go
@@ -99,10 +99,22 @@ func compatTripleConfig(c *global.TripleConfig) *config.TripleConfig {
 		return nil
 	}
 	return &config.TripleConfig{
-		KeepAliveInterval:    c.KeepAliveInterval,
-		KeepAliveTimeout:     c.KeepAliveTimeout,
 		MaxServerSendMsgSize: c.MaxServerSendMsgSize,
 		MaxServerRecvMsgSize: c.MaxServerRecvMsgSize,
+		Http3:                compatHttp3Config(c.Http3),
+
+		KeepAliveInterval: c.KeepAliveInterval,
+		KeepAliveTimeout:  c.KeepAliveTimeout,
+	}
+}
+
+// just for compat
+func compatHttp3Config(c *global.Http3Config) *config.Http3Config {
+	if c == nil {
+		return nil
+	}
+	return &config.Http3Config{
+		Enable: c.Enable,
 	}
 }
 
@@ -276,6 +288,73 @@ func compatConsumerConfig(c *global.ConsumerConfig) *config.ConsumerConfig {
 		FilterConf:                     c.FilterConf,
 		MaxWaitTimeForServiceDiscovery: c.MaxWaitTimeForServiceDiscovery,
 		MeshEnabled:                    c.MeshEnabled,
+		References:                     compatReferences(c.References),
+	}
+}
+
+func compatReferences(c map[string]*global.ReferenceConfig) map[string]*config.ReferenceConfig {
+	refs := make(map[string]*config.ReferenceConfig, len(c))
+	for name, ref := range c {
+		refs[name] = &config.ReferenceConfig{
+			InterfaceName:        ref.InterfaceName,
+			Check:                ref.Check,
+			URL:                  ref.URL,
+			Filter:               ref.Filter,
+			Protocol:             ref.Protocol,
+			RegistryIDs:          ref.RegistryIDs,
+			Cluster:              ref.Cluster,
+			Loadbalance:          ref.Loadbalance,
+			Retries:              ref.Retries,
+			Group:                ref.Group,
+			Version:              ref.Version,
+			Serialization:        ref.Serialization,
+			ProvidedBy:           ref.ProvidedBy,
+			MethodsConfig:        compatMethod(ref.MethodsConfig),
+			ProtocolClientConfig: compatProtocolClientConfig(ref.ProtocolClientConfig),
+			Async:                ref.Async,
+			Params:               ref.Params,
+			Generic:              ref.Generic,
+			Sticky:               ref.Sticky,
+			RequestTimeout:       ref.RequestTimeout,
+			ForceTag:             ref.ForceTag,
+			TracingKey:           ref.TracingKey,
+			MeshProviderPort:     ref.MeshProviderPort,
+		}
+	}
+	return refs
+}
+
+// TODO: merge compatGlobalMethod() and compatGlobalMethodConfig
+func compatMethod(m []*global.MethodConfig) []*config.MethodConfig {
+	methods := make([]*config.MethodConfig, 0, len(m))
+	for _, method := range m {
+		methods = append(methods, &config.MethodConfig{
+			InterfaceId:                 method.InterfaceId,
+			InterfaceName:               method.InterfaceName,
+			Name:                        method.Name,
+			Retries:                     method.Retries,
+			LoadBalance:                 method.LoadBalance,
+			Weight:                      method.Weight,
+			TpsLimitInterval:            method.TpsLimitInterval,
+			TpsLimitRate:                method.TpsLimitRate,
+			TpsLimitStrategy:            method.TpsLimitStrategy,
+			ExecuteLimit:                method.ExecuteLimit,
+			ExecuteLimitRejectedHandler: method.ExecuteLimitRejectedHandler,
+			Sticky:                      method.Sticky,
+			RequestTimeout:              method.RequestTimeout,
+		})
+	}
+	return methods
+}
+
+// just for compat
+func compatProtocolClientConfig(c *global.ClientProtocolConfig) *config.ClientProtocolConfig {
+	if c == nil {
+		return nil
+	}
+	return &config.ClientProtocolConfig{
+		Name:         c.Name,
+		TripleConfig: compatTripleConfig(c.TripleConfig),
 	}
 }
 
@@ -422,6 +501,7 @@ func compatInstanceOptions(cr *config.RootConfig, rc *InstanceOptions) {
 	if cr == nil {
 		return
 	}
+
 	proCompat := make(map[string]*global.ProtocolConfig)
 	for k, v := range cr.Protocols {
 		proCompat[k] = compatGlobalProtocolConfig(v)
@@ -470,13 +550,25 @@ func compatGlobalTripleConfig(c *config.TripleConfig) *global.TripleConfig {
 		return nil
 	}
 	return &global.TripleConfig{
-		KeepAliveInterval:    c.KeepAliveInterval,
-		KeepAliveTimeout:     c.KeepAliveTimeout,
+		KeepAliveInterval: c.KeepAliveInterval,
+		KeepAliveTimeout:  c.KeepAliveTimeout,
+		Http3:             compatGlobalHttp3Config(c.Http3),
+
 		MaxServerSendMsgSize: c.MaxServerSendMsgSize,
 		MaxServerRecvMsgSize: c.MaxServerRecvMsgSize,
 	}
 }
 
+// just for compat
+func compatGlobalHttp3Config(c *config.Http3Config) *global.Http3Config {
+	if c == nil {
+		return nil
+	}
+	return &global.Http3Config{
+		Enable: c.Enable,
+	}
+}
+
 func compatGlobalRegistryConfig(c *config.RegistryConfig) *global.RegistryConfig {
 	if c == nil {
 		return nil
@@ -674,33 +766,35 @@ func compatGlobalReferences(c map[string]*config.ReferenceConfig) map[string]*gl
 	refs := make(map[string]*global.ReferenceConfig, len(c))
 	for name, ref := range c {
 		refs[name] = &global.ReferenceConfig{
-			InterfaceName:    ref.InterfaceName,
-			Check:            ref.Check,
-			URL:              ref.URL,
-			Filter:           ref.Filter,
-			Protocol:         ref.Protocol,
-			RegistryIDs:      ref.RegistryIDs,
-			Cluster:          ref.Cluster,
-			Loadbalance:      ref.Loadbalance,
-			Retries:          ref.Retries,
-			Group:            ref.Group,
-			Version:          ref.Version,
-			Serialization:    ref.Serialization,
-			ProvidedBy:       ref.ProvidedBy,
-			MethodsConfig:    compatGlobalMethod(ref.Methods),
-			Async:            ref.Async,
-			Params:           ref.Params,
-			Generic:          ref.Generic,
-			Sticky:           ref.Sticky,
-			RequestTimeout:   ref.RequestTimeout,
-			ForceTag:         ref.ForceTag,
-			TracingKey:       ref.TracingKey,
-			MeshProviderPort: ref.MeshProviderPort,
+			InterfaceName:        ref.InterfaceName,
+			Check:                ref.Check,
+			URL:                  ref.URL,
+			Filter:               ref.Filter,
+			Protocol:             ref.Protocol,
+			RegistryIDs:          ref.RegistryIDs,
+			Cluster:              ref.Cluster,
+			Loadbalance:          ref.Loadbalance,
+			Retries:              ref.Retries,
+			Group:                ref.Group,
+			Version:              ref.Version,
+			Serialization:        ref.Serialization,
+			ProvidedBy:           ref.ProvidedBy,
+			MethodsConfig:        compatGlobalMethod(ref.MethodsConfig),
+			ProtocolClientConfig: compatGlobalProtocolClientConfig(ref.ProtocolClientConfig),
+			Async:                ref.Async,
+			Params:               ref.Params,
+			Generic:              ref.Generic,
+			Sticky:               ref.Sticky,
+			RequestTimeout:       ref.RequestTimeout,
+			ForceTag:             ref.ForceTag,
+			TracingKey:           ref.TracingKey,
+			MeshProviderPort:     ref.MeshProviderPort,
 		}
 	}
 	return refs
 }
 
+// TODO: merge compatGlobalMethod() and compatGlobalMethodConfig
 func compatGlobalMethod(m []*config.MethodConfig) []*global.MethodConfig {
 	methods := make([]*global.MethodConfig, 0, len(m))
 	for _, method := range m {
@@ -723,6 +817,17 @@ func compatGlobalMethod(m []*config.MethodConfig) []*global.MethodConfig {
 	return methods
 }
 
+// just for compat
+func compatGlobalProtocolClientConfig(c *config.ClientProtocolConfig) *global.ClientProtocolConfig {
+	if c == nil {
+		return nil
+	}
+	return &global.ClientProtocolConfig{
+		Name:         c.Name,
+		TripleConfig: compatGlobalTripleConfig(c.TripleConfig),
+	}
+}
+
 func compatGlobalMetricConfig(c *config.MetricsConfig) *global.MetricsConfig {
 	if c == nil {
 		return nil
diff --git a/global/protocol_client_config.go b/config/client_protocol_config.go
similarity index 61%
copy from global/protocol_client_config.go
copy to config/client_protocol_config.go
index 6d9f1a594..e801a0f78 100644
--- a/global/protocol_client_config.go
+++ b/config/client_protocol_config.go
@@ -15,36 +15,12 @@
  * limitations under the License.
  */
 
-package global
+package config
 
-import (
-	"dubbo.apache.org/dubbo-go/v3/common/constant"
-)
-
-// TODO: find a better name replace ProtocolClientConfig
-type ProtocolClientConfig struct {
+// ClientProtocolConfig represents the config of client's protocol
+type ClientProtocolConfig struct {
 	// TODO: maybe we could use this field
 	Name string `yaml:"name" json:"name,omitempty" property:"name"`
 
 	TripleConfig *TripleConfig `yaml:"triple" json:"triple,omitempty" property:"triple"`
 }
-
-// DefaultProtocolConfig returns a default ProtocolConfig instance.
-func DefaultProtocolClientConfig() *ProtocolClientConfig {
-	return &ProtocolClientConfig{
-		Name:         constant.TriProtocol,
-		TripleConfig: DefaultTripleConfig(),
-	}
-}
-
-// Clone a new ProtocolConfig
-func (c *ProtocolClientConfig) Clone() *ProtocolClientConfig {
-	if c == nil {
-		return nil
-	}
-
-	return &ProtocolClientConfig{
-		Name:         c.Name,
-		TripleConfig: c.TripleConfig.Clone(),
-	}
-}
diff --git a/config/triple_config.go b/config/http3_config.go
similarity index 53%
copy from config/triple_config.go
copy to config/http3_config.go
index 2fbd99909..bede6e551 100644
--- a/config/triple_config.go
+++ b/config/http3_config.go
@@ -17,12 +17,18 @@
 
 package config
 
-type TripleConfig struct {
-	KeepAliveInterval string `yaml:"keep-alive-interval" json:"keep-alive-interval,omitempty" property:"keep-alive-interval"`
-	KeepAliveTimeout  string `yaml:"keep-alive-timeout" json:"keep-alive-timeout,omitempty" property:"keep-alive-timeout"`
+// Http3Config represents the config of http3
+type Http3Config struct {
+	// Whether to enable HTTP/3 support.
+	// The default value is false.
+	Enable bool `yaml:"enable" json:"enable,omitempty"`
+	// TODO: add more params about http3
 
-	// MaxServerSendMsgSize max size of server send message, 1mb=1000kb=1000000b 1mib=1024kb=1048576b.
-	// more detail to see https://pkg.go.dev/github.com/dustin/go-humanize#pkg-constants
-	MaxServerSendMsgSize string `yaml:"max-server-send-msg-size" json:"max-server-send-msg-size,omitempty"` // MaxServerRecvMsgSize max size of server receive message
-	MaxServerRecvMsgSize string `yaml:"max-server-recv-msg-size" json:"max-server-recv-msg-size,omitempty"`
+	// TODO: negotiation implementation
+	// ref: https://quic-go.net/docs/http3/server/#advertising-http3-via-alt-svc
+	//
+	// Whether to enable HTTP/3 negotiation.
+	// If set to false, HTTP/2 alt-svc negotiation will be skipped,
+	// enabling HTTP/3 but disabling HTTP/2 on the consumer side.
+	// negotiation bool
 }
diff --git a/config/reference_config.go b/config/reference_config.go
index 88bb1b627..9657f931d 100644
--- a/config/reference_config.go
+++ b/config/reference_config.go
@@ -52,21 +52,25 @@ type ReferenceConfig struct {
 	urls       []*common.URL
 	rootConfig *RootConfig
 
-	id               string
-	InterfaceName    string            `yaml:"interface"  json:"interface,omitempty" property:"interface"`
-	Check            *bool             `yaml:"check"  json:"check,omitempty" property:"check"`
-	URL              string            `yaml:"url"  json:"url,omitempty" property:"url"`
-	Filter           string            `yaml:"filter" json:"filter,omitempty" property:"filter"`
-	Protocol         string            `yaml:"protocol"  json:"protocol,omitempty" property:"protocol"`
-	RegistryIDs      []string          `yaml:"registry-ids"  json:"registry-ids,omitempty"  property:"registry-ids"`
-	Cluster          string            `yaml:"cluster"  json:"cluster,omitempty" property:"cluster"`
-	Loadbalance      string            `yaml:"loadbalance"  json:"loadbalance,omitempty" property:"loadbalance"`
-	Retries          string            `yaml:"retries"  json:"retries,omitempty" property:"retries"`
-	Group            string            `yaml:"group"  json:"group,omitempty" property:"group"`
-	Version          string            `yaml:"version"  json:"version,omitempty" property:"version"`
-	Serialization    string            `yaml:"serialization" json:"serialization" property:"serialization"`
-	ProvidedBy       string            `yaml:"provided_by"  json:"provided_by,omitempty" property:"provided_by"`
-	Methods          []*MethodConfig   `yaml:"methods"  json:"methods,omitempty" property:"methods"`
+	id            string
+	InterfaceName string   `yaml:"interface"  json:"interface,omitempty" property:"interface"`
+	Check         *bool    `yaml:"check"  json:"check,omitempty" property:"check"`
+	URL           string   `yaml:"url"  json:"url,omitempty" property:"url"`
+	Filter        string   `yaml:"filter" json:"filter,omitempty" property:"filter"`
+	Protocol      string   `yaml:"protocol"  json:"protocol,omitempty" property:"protocol"`
+	RegistryIDs   []string `yaml:"registry-ids"  json:"registry-ids,omitempty"  property:"registry-ids"`
+	Cluster       string   `yaml:"cluster"  json:"cluster,omitempty" property:"cluster"`
+	Loadbalance   string   `yaml:"loadbalance"  json:"loadbalance,omitempty" property:"loadbalance"`
+	Retries       string   `yaml:"retries"  json:"retries,omitempty" property:"retries"`
+	Group         string   `yaml:"group"  json:"group,omitempty" property:"group"`
+	Version       string   `yaml:"version"  json:"version,omitempty" property:"version"`
+	Serialization string   `yaml:"serialization" json:"serialization" property:"serialization"`
+	ProvidedBy    string   `yaml:"provided_by"  json:"provided_by,omitempty" property:"provided_by"`
+
+	MethodsConfig []*MethodConfig `yaml:"methods"  json:"methods,omitempty" property:"methods"`
+	// TODO: rename protocol_config to protocol when publish 4.0.0.
+	ProtocolClientConfig *ClientProtocolConfig `yaml:"protocol_config" json:"protocol_config,omitempty" property:"protocol_config"`
+
 	Async            bool              `yaml:"async"  json:"async,omitempty" property:"async"`
 	Params           map[string]string `yaml:"params"  json:"params,omitempty" property:"params"`
 	Generic          string            `yaml:"generic"  json:"generic,omitempty" property:"generic"`
@@ -84,7 +88,7 @@ func (rc *ReferenceConfig) Prefix() string {
 }
 
 func (rc *ReferenceConfig) Init(root *RootConfig) error {
-	for _, method := range rc.Methods {
+	for _, method := range rc.MethodsConfig {
 		if err := method.Init(); err != nil {
 			return err
 		}
@@ -364,7 +368,7 @@ func (rc *ReferenceConfig) getURLMap() url.Values {
 	}
 	urlMap.Set(constant.ReferenceFilterKey, mergeValue(rc.Filter, "", defaultReferenceFilter))
 
-	for _, v := range rc.Methods {
+	for _, v := range rc.MethodsConfig {
 		urlMap.Set("methods."+v.Name+"."+constant.LoadbalanceKey, v.LoadBalance)
 		urlMap.Set("methods."+v.Name+"."+constant.RetriesKey, v.Retries)
 		urlMap.Set("methods."+v.Name+"."+constant.StickyKey, strconv.FormatBool(v.Sticky))
@@ -402,7 +406,7 @@ func (rc *ReferenceConfig) postProcessConfig(url *common.URL) {
 // newEmptyReferenceConfig returns empty ReferenceConfig
 func newEmptyReferenceConfig() *ReferenceConfig {
 	newReferenceConfig := &ReferenceConfig{}
-	newReferenceConfig.Methods = make([]*MethodConfig, 0, 8)
+	newReferenceConfig.MethodsConfig = make([]*MethodConfig, 0, 8)
 	newReferenceConfig.Params = make(map[string]string, 8)
 	return newReferenceConfig
 }
@@ -485,12 +489,12 @@ func (pcb *ReferenceConfigBuilder) SetProvidedBy(providedBy string) *ReferenceCo
 }
 
 func (pcb *ReferenceConfigBuilder) SetMethodConfig(methodConfigs []*MethodConfig) *ReferenceConfigBuilder {
-	pcb.referenceConfig.Methods = methodConfigs
+	pcb.referenceConfig.MethodsConfig = methodConfigs
 	return pcb
 }
 
 func (pcb *ReferenceConfigBuilder) AddMethodConfig(methodConfig *MethodConfig) *ReferenceConfigBuilder {
-	pcb.referenceConfig.Methods = append(pcb.referenceConfig.Methods, methodConfig)
+	pcb.referenceConfig.MethodsConfig = append(pcb.referenceConfig.MethodsConfig, methodConfig)
 	return pcb
 }
 
diff --git a/config/triple_config.go b/config/triple_config.go
index 2fbd99909..5a0561112 100644
--- a/config/triple_config.go
+++ b/config/triple_config.go
@@ -17,12 +17,16 @@
 
 package config
 
+// TripleConfig represents the config of triple protocol
 type TripleConfig struct {
-	KeepAliveInterval string `yaml:"keep-alive-interval" json:"keep-alive-interval,omitempty" property:"keep-alive-interval"`
-	KeepAliveTimeout  string `yaml:"keep-alive-timeout" json:"keep-alive-timeout,omitempty" property:"keep-alive-timeout"`
-
 	// MaxServerSendMsgSize max size of server send message, 1mb=1000kb=1000000b 1mib=1024kb=1048576b.
 	// more detail to see https://pkg.go.dev/github.com/dustin/go-humanize#pkg-constants
-	MaxServerSendMsgSize string `yaml:"max-server-send-msg-size" json:"max-server-send-msg-size,omitempty"` // MaxServerRecvMsgSize max size of server receive message
+	MaxServerSendMsgSize string `yaml:"max-server-send-msg-size" json:"max-server-send-msg-size,omitempty"`
+	// MaxServerRecvMsgSize max size of server receive message
 	MaxServerRecvMsgSize string `yaml:"max-server-recv-msg-size" json:"max-server-recv-msg-size,omitempty"`
+
+	Http3 *Http3Config `yaml:"http3" json:"http3,omitempty" property:"http3"`
+
+	KeepAliveInterval string `yaml:"keep-alive-interval" json:"keep-alive-interval,omitempty" property:"keep-alive-interval"`
+	KeepAliveTimeout  string `yaml:"keep-alive-timeout" json:"keep-alive-timeout,omitempty" property:"keep-alive-timeout"`
 }
diff --git a/global/protocol_client_config.go b/global/client_protocol_config.go
similarity index 75%
copy from global/protocol_client_config.go
copy to global/client_protocol_config.go
index 6d9f1a594..4856d86c0 100644
--- a/global/protocol_client_config.go
+++ b/global/client_protocol_config.go
@@ -21,29 +21,29 @@ import (
 	"dubbo.apache.org/dubbo-go/v3/common/constant"
 )
 
-// TODO: find a better name replace ProtocolClientConfig
-type ProtocolClientConfig struct {
+// ClientProtocolConfig represents the config of client's protocol
+type ClientProtocolConfig struct {
 	// TODO: maybe we could use this field
 	Name string `yaml:"name" json:"name,omitempty" property:"name"`
 
 	TripleConfig *TripleConfig `yaml:"triple" json:"triple,omitempty" property:"triple"`
 }
 
-// DefaultProtocolConfig returns a default ProtocolConfig instance.
-func DefaultProtocolClientConfig() *ProtocolClientConfig {
-	return &ProtocolClientConfig{
+// DefaultClientProtocolConfig returns a default ClientProtocolConfig instance.
+func DefaultClientProtocolConfig() *ClientProtocolConfig {
+	return &ClientProtocolConfig{
 		Name:         constant.TriProtocol,
 		TripleConfig: DefaultTripleConfig(),
 	}
 }
 
-// Clone a new ProtocolConfig
-func (c *ProtocolClientConfig) Clone() *ProtocolClientConfig {
+// Clone a new ClientProtocolConfig
+func (c *ClientProtocolConfig) Clone() *ClientProtocolConfig {
 	if c == nil {
 		return nil
 	}
 
-	return &ProtocolClientConfig{
+	return &ClientProtocolConfig{
 		Name:         c.Name,
 		TripleConfig: c.TripleConfig.Clone(),
 	}
diff --git a/global/config_test.go b/global/config_test.go
index 4e7727ae7..c436a7d75 100644
--- a/global/config_test.go
+++ b/global/config_test.go
@@ -130,6 +130,13 @@ func TestCloneConfig(t *testing.T) {
 		CheckCompleteInequality(t, c, clone)
 	})
 
+	t.Run("ClientProtocolConfig", func(t *testing.T) {
+		c := DefaultClientProtocolConfig()
+		InitCheckCompleteInequality(t, c)
+		clone := c.Clone()
+		CheckCompleteInequality(t, c, clone)
+	})
+
 	t.Run("ProviderConfig", func(t *testing.T) {
 		c := DefaultProviderConfig()
 		InitCheckCompleteInequality(t, c)
@@ -171,6 +178,20 @@ func TestCloneConfig(t *testing.T) {
 		clone := c.Clone()
 		CheckCompleteInequality(t, c, clone)
 	})
+
+	t.Run("TripleConfig", func(t *testing.T) {
+		c := DefaultTripleConfig()
+		InitCheckCompleteInequality(t, c)
+		clone := c.Clone()
+		CheckCompleteInequality(t, c, clone)
+	})
+
+	t.Run("Http3Config", func(t *testing.T) {
+		c := DefaultHttp3Config()
+		InitCheckCompleteInequality(t, c)
+		clone := c.Clone()
+		CheckCompleteInequality(t, c, clone)
+	})
 }
 
 func InitCheckCompleteInequality(t *testing.T, origin any) {
diff --git a/global/protocol_client_config.go b/global/http3_config.go
similarity index 51%
rename from global/protocol_client_config.go
rename to global/http3_config.go
index 6d9f1a594..e191dfbca 100644
--- a/global/protocol_client_config.go
+++ b/global/http3_config.go
@@ -17,34 +17,34 @@
 
 package global
 
-import (
-	"dubbo.apache.org/dubbo-go/v3/common/constant"
-)
+// Http3Config represents the config of http3
+type Http3Config struct {
+	// Whether to enable HTTP/3 support.
+	// The default value is false.
+	Enable bool `yaml:"enable" json:"enable,omitempty"`
+	// TODO: add more params about http3
 
-// TODO: find a better name replace ProtocolClientConfig
-type ProtocolClientConfig struct {
-	// TODO: maybe we could use this field
-	Name string `yaml:"name" json:"name,omitempty" property:"name"`
-
-	TripleConfig *TripleConfig `yaml:"triple" json:"triple,omitempty" property:"triple"`
+	// TODO: negotiation implementation
+	// ref: https://quic-go.net/docs/http3/server/#advertising-http3-via-alt-svc
+	//
+	// Whether to enable HTTP/3 negotiation.
+	// If set to false, HTTP/2 alt-svc negotiation will be skipped,
+	// enabling HTTP/3 but disabling HTTP/2 on the consumer side.
+	// negotiation bool
 }
 
-// DefaultProtocolConfig returns a default ProtocolConfig instance.
-func DefaultProtocolClientConfig() *ProtocolClientConfig {
-	return &ProtocolClientConfig{
-		Name:         constant.TriProtocol,
-		TripleConfig: DefaultTripleConfig(),
-	}
+// DefaultHttp3Config returns a default Http3Config instance.
+func DefaultHttp3Config() *Http3Config {
+	return &Http3Config{}
 }
 
-// Clone a new ProtocolConfig
-func (c *ProtocolClientConfig) Clone() *ProtocolClientConfig {
-	if c == nil {
+// Clone a new Http3Config
+func (t *Http3Config) Clone() *Http3Config {
+	if t == nil {
 		return nil
 	}
 
-	return &ProtocolClientConfig{
-		Name:         c.Name,
-		TripleConfig: c.TripleConfig.Clone(),
+	return &Http3Config{
+		Enable: t.Enable,
 	}
 }
diff --git a/global/reference_config.go b/global/reference_config.go
index 013068a94..d7db62751 100644
--- a/global/reference_config.go
+++ b/global/reference_config.go
@@ -46,8 +46,9 @@ type ReferenceConfig struct {
 	MeshProviderPort int               `yaml:"mesh-provider-port" json:"mesh-provider-port,omitempty" property:"mesh-provider-port"`
 
 	// config
-	MethodsConfig        []*MethodConfig       `yaml:"methods"  json:"methods,omitempty" property:"methods"`
-	ProtocolClientConfig *ProtocolClientConfig `yaml:"protocol-config" json:"protocol-config,omitempty" property:"protocol-config"`
+	MethodsConfig []*MethodConfig `yaml:"methods"  json:"methods,omitempty" property:"methods"`
+	// TODO: rename protocol_config to protocol when publish 4.0.0.
+	ProtocolClientConfig *ClientProtocolConfig `yaml:"protocol_config" json:"protocol_config,omitempty" property:"protocol_config"`
 
 	// TODO: Deprecated:use TripleConfig
 	// remove KeepAliveInterval and KeepAliveInterval in version 4.0.0
@@ -64,7 +65,7 @@ func DefaultReferenceConfig() *ReferenceConfig {
 		// use Triple protocol by default
 		//Protocol: "tri",
 		MethodsConfig:        make([]*MethodConfig, 0, 8),
-		ProtocolClientConfig: DefaultProtocolClientConfig(),
+		ProtocolClientConfig: DefaultClientProtocolConfig(),
 		//Params:   make(map[string]string, 8),
 	}
 }
@@ -141,6 +142,9 @@ func (c *ReferenceConfig) GetOptions() []ReferenceOption {
 	if c.KeepAliveTimeout != "" {
 		refOpts = append(refOpts, WithReference_KeepAliveTimeout(c.KeepAliveTimeout))
 	}
+	if c.ProtocolClientConfig != nil {
+		refOpts = append(refOpts, WithReference_ProtocolClientConfig(c.ProtocolClientConfig))
+	}
 	return refOpts
 }
 
@@ -343,3 +347,9 @@ func WithReference_KeepAliveTimeout(timeout string) ReferenceOption {
 		cfg.KeepAliveTimeout = timeout
 	}
 }
+
+func WithReference_ProtocolClientConfig(protocolClientConfig *ClientProtocolConfig) ReferenceOption {
+	return func(cfg *ReferenceConfig) {
+		cfg.ProtocolClientConfig = protocolClientConfig.Clone()
+	}
+}
diff --git a/global/triple_config.go b/global/triple_config.go
index a5fcf7a86..83b57c63d 100644
--- a/global/triple_config.go
+++ b/global/triple_config.go
@@ -17,19 +17,36 @@
 
 package global
 
-// TODO: Should the server and client configurations be separated?
+// TODO: Find an ideal way to separate the triple config of server and client.
+
+// TripleConfig represents the config of triple protocol
 type TripleConfig struct {
-	KeepAliveInterval string `yaml:"keep-alive-interval" json:"keep-alive-interval,omitempty" property:"keep-alive-interval"`
-	KeepAliveTimeout  string `yaml:"keep-alive-timeout" json:"keep-alive-timeout,omitempty" property:"keep-alive-timeout"`
+	//
+	// for server
+	//
 
 	// MaxServerSendMsgSize max size of server send message, 1mb=1000kb=1000000b 1mib=1024kb=1048576b.
 	// more detail to see https://pkg.go.dev/github.com/dustin/go-humanize#pkg-constants
-	MaxServerSendMsgSize string `yaml:"max-server-send-msg-size" json:"max-server-send-msg-size,omitempty"` // MaxServerRecvMsgSize max size of server receive message
+	MaxServerSendMsgSize string `yaml:"max-server-send-msg-size" json:"max-server-send-msg-size,omitempty"`
+	// MaxServerRecvMsgSize max size of server receive message
 	MaxServerRecvMsgSize string `yaml:"max-server-recv-msg-size" json:"max-server-recv-msg-size,omitempty"`
+
+	// the config of http3 transport
+	Http3 *Http3Config `yaml:"http3" json:"http3,omitempty"`
+
+	//
+	// for client
+	//
+
+	KeepAliveInterval string `yaml:"keep-alive-interval" json:"keep-alive-interval,omitempty" property:"keep-alive-interval"`
+	KeepAliveTimeout  string `yaml:"keep-alive-timeout" json:"keep-alive-timeout,omitempty" property:"keep-alive-timeout"`
 }
 
+// DefaultTripleConfig returns a default TripleConfig instance.
 func DefaultTripleConfig() *TripleConfig {
-	return &TripleConfig{}
+	return &TripleConfig{
+		Http3: DefaultHttp3Config(),
+	}
 }
 
 // Clone a new TripleConfig
@@ -39,9 +56,11 @@ func (t *TripleConfig) Clone() *TripleConfig {
 	}
 
 	return &TripleConfig{
-		KeepAliveInterval:    t.KeepAliveInterval,
-		KeepAliveTimeout:     t.KeepAliveTimeout,
 		MaxServerSendMsgSize: t.MaxServerSendMsgSize,
 		MaxServerRecvMsgSize: t.MaxServerRecvMsgSize,
+		Http3:                t.Http3.Clone(),
+
+		KeepAliveInterval: t.KeepAliveInterval,
+		KeepAliveTimeout:  t.KeepAliveTimeout,
 	}
 }
diff --git a/go.mod b/go.mod
index 54b05cc46..28e64ceaa 100644
--- a/go.mod
+++ b/go.mod
@@ -23,7 +23,7 @@ require (
 	github.com/go-playground/validator/v10 v10.12.0
 	github.com/go-resty/resty/v2 v2.7.0
 	github.com/golang/mock v1.6.0
-	github.com/golang/protobuf v1.5.3
+	github.com/golang/protobuf v1.5.4
 	github.com/google/go-cmp v0.6.0
 	github.com/google/uuid v1.3.1
 	github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645
@@ -42,10 +42,11 @@ require (
 	github.com/opentracing/opentracing-go v1.2.0
 	github.com/pkg/errors v0.9.1
 	github.com/polarismesh/polaris-go v1.3.0
-	github.com/prometheus/client_golang v1.13.0
-	github.com/prometheus/common v0.37.0
+	github.com/prometheus/client_golang v1.19.1
+	github.com/prometheus/common v0.48.0
+	github.com/quic-go/quic-go v0.52.0
 	github.com/sirupsen/logrus v1.8.1
-	github.com/stretchr/testify v1.8.4
+	github.com/stretchr/testify v1.9.0
 	github.com/ugorji/go/codec v1.2.6
 	go.etcd.io/etcd/api/v3 v3.5.7
 	go.etcd.io/etcd/client/v3 v3.5.7
@@ -61,9 +62,9 @@ require (
 	go.opentelemetry.io/otel/trace v1.21.0
 	go.uber.org/atomic v1.10.0
 	go.uber.org/zap v1.21.0
-	golang.org/x/net v0.23.0
+	golang.org/x/net v0.28.0
 	google.golang.org/grpc v1.59.0
-	google.golang.org/protobuf v1.31.0
+	google.golang.org/protobuf v1.33.0
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1
 	gopkg.in/yaml.v2 v2.4.0
 )
@@ -85,6 +86,7 @@ require (
 	github.com/go-playground/locales v0.14.1 // indirect
 	github.com/go-playground/universal-translator v0.18.1 // indirect
 	github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
+	github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
 	github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
@@ -100,19 +102,20 @@ require (
 	github.com/leodido/go-urn v1.2.2 // indirect
 	github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
 	github.com/mattn/go-isatty v0.0.16 // indirect
-	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/mitchellh/copystructure v1.2.0 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/reflectwalk v1.0.2 // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/mschoch/smat v0.2.0 // indirect
+	github.com/onsi/ginkgo/v2 v2.11.0 // indirect
 	github.com/openzipkin/zipkin-go v0.4.2 // indirect
 	github.com/pelletier/go-toml v1.9.3 // indirect
 	github.com/pierrec/lz4 v2.6.1+incompatible // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
-	github.com/prometheus/client_model v0.3.0 // indirect
-	github.com/prometheus/procfs v0.8.0 // indirect
+	github.com/prometheus/client_model v0.5.0 // indirect
+	github.com/prometheus/procfs v0.12.0 // indirect
+	github.com/quic-go/qpack v0.5.1 // indirect
 	github.com/shirou/gopsutil/v3 v3.22.2 // indirect
 	github.com/spaolacci/murmur3 v1.1.0 // indirect
 	github.com/spf13/afero v1.6.0 // indirect
@@ -120,7 +123,7 @@ require (
 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/spf13/viper v1.8.1 // indirect
-	github.com/stretchr/objx v0.5.0 // indirect
+	github.com/stretchr/objx v0.5.2 // indirect
 	github.com/subosito/gotenv v1.2.0 // indirect
 	github.com/tklauser/go-sysconf v0.3.10 // indirect
 	github.com/tklauser/numcpus v0.4.0 // indirect
@@ -130,12 +133,15 @@ require (
 	go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect
 	go.opentelemetry.io/otel/metric v1.21.0 // indirect
 	go.opentelemetry.io/proto/otlp v1.0.0 // indirect
+	go.uber.org/mock v0.5.0 // indirect
 	go.uber.org/multierr v1.8.0 // indirect
-	golang.org/x/crypto v0.21.0 // indirect
-	golang.org/x/sync v0.3.0 // indirect
-	golang.org/x/sys v0.18.0 // indirect
-	golang.org/x/text v0.14.0 // indirect
+	golang.org/x/crypto v0.26.0 // indirect
+	golang.org/x/mod v0.18.0 // indirect
+	golang.org/x/sync v0.8.0 // indirect
+	golang.org/x/sys v0.23.0 // indirect
+	golang.org/x/text v0.17.0 // indirect
 	golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
+	golang.org/x/tools v0.22.0 // indirect
 	google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
diff --git a/go.sum b/go.sum
index 950592ab1..1e3ca1800 100644
--- a/go.sum
+++ b/go.sum
@@ -240,12 +240,10 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
 github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
-github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
 github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
-github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
 github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -268,6 +266,8 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyL
 github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
 github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
 github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@@ -316,8 +316,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
@@ -544,8 +544,6 @@ github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peK
 github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
-github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
 github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
@@ -604,7 +602,11 @@ github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 h1:Yl0tPBa8QPjG
 github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852/go.mod h1:eqOVx5Vwu4gd2mmMZvVZsgIqNSaW3xxRThUJ0k/TPk4=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
+github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
 github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
+github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
 github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
 github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
@@ -657,16 +659,16 @@ github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqr
 github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
 github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
 github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
-github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
-github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
+github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
+github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
-github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
+github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
+github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
 github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
 github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
@@ -677,8 +679,8 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8
 github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
 github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
-github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
-github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
+github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
+github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@@ -688,9 +690,13 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
 github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
-github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
-github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
+github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
+github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
+github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
+github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
+github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@@ -753,8 +759,9 @@ github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5J
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -764,8 +771,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ=
@@ -877,6 +884,8 @@ go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0
 go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
 go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
+go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
 go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
@@ -903,8 +912,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
-golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
+golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -947,6 +956,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
+golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -997,12 +1008,10 @@ golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy
 golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211105192438-b53810dc28af/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
-golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1017,7 +1026,6 @@ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ
 golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1030,8 +1038,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
-golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1118,8 +1126,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
+golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1133,8 +1141,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1207,6 +1215,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
+golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1351,8 +1361,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
-google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/protocol/options.go b/protocol/options.go
index c3f1e58e2..28629f7c0 100644
--- a/protocol/options.go
+++ b/protocol/options.go
@@ -120,13 +120,13 @@ func NewServerOptions(opts ...ServerOption) *ServerOptions {
 }
 
 type ClientOptions struct {
-	ProtocolClient *global.ProtocolClientConfig
+	ProtocolClient *global.ClientProtocolConfig
 
 	ID string
 }
 
 func defaultClientOptions() *ClientOptions {
-	return &ClientOptions{ProtocolClient: global.DefaultProtocolClientConfig()}
+	return &ClientOptions{ProtocolClient: global.DefaultClientProtocolConfig()}
 }
 
 func NewClientOptions(opts ...ClientOption) *ClientOptions {
diff --git a/protocol/triple/client.go b/protocol/triple/client.go
index f52b169db..34022421c 100644
--- a/protocol/triple/client.go
+++ b/protocol/triple/client.go
@@ -35,6 +35,9 @@ import (
 	"github.com/dustin/go-humanize"
 
 	"golang.org/x/net/http2"
+
+	"github.com/quic-go/quic-go"
+	"github.com/quic-go/quic-go/http3"
 )
 
 import (
@@ -184,26 +187,48 @@ func newClientManager(url *common.URL) (*clientManager, error) {
 		}
 	}
 
-	cliKeepAliveOpts, keepAliveInterval, keepAliveTimeout, genKeepAliveOptsErr := genKeepAliveOpts(url)
+	var tripleConf *global.TripleConfig
+
+	tripleConfRaw, ok := url.GetAttribute(constant.TripleConfigKey)
+	if ok {
+		tripleConf = tripleConfRaw.(*global.TripleConfig)
+	}
+
+	// handle keepalive options
+	cliKeepAliveOpts, keepAliveInterval, keepAliveTimeout, genKeepAliveOptsErr := genKeepAliveOptions(url, tripleConf)
 	if genKeepAliveOptsErr != nil {
 		logger.Errorf("genKeepAliveOpts err: %v", genKeepAliveOptsErr)
 		return nil, genKeepAliveOptsErr
 	}
-
 	cliOpts = append(cliOpts, cliKeepAliveOpts...)
 
+	// handle http transport of triple protocol
 	var transport http.RoundTripper
-	callType := url.GetParam(constant.CallHTTPTypeKey, constant.CallHTTP2)
-	switch callType {
+
+	var callProtocol string
+	if tripleConf != nil && tripleConf.Http3 != nil && tripleConf.Http3.Enable {
+		callProtocol = constant.CallHTTP3
+	} else {
+		// HTTP default type is HTTP/2.
+		callProtocol = constant.CallHTTP2
+	}
+
+	switch callProtocol {
+	// This case might be for backward compatibility,
+	// it's not useful for the Triple protocol, HTTP/1 lacks trailer functionality.
+	// Triple protocol only supports HTTP/2 and HTTP/3.
 	case constant.CallHTTP:
 		transport = &http.Transport{
 			TLSClientConfig: cfg,
 		}
 		cliOpts = append(cliOpts, tri.WithTriple())
 	case constant.CallHTTP2:
+		// TODO: Enrich the http2 transport config for triple protocol.
 		if tlsFlag {
 			transport = &http2.Transport{
 				TLSClientConfig: cfg,
+				ReadIdleTimeout: keepAliveInterval,
+				PingTimeout:     keepAliveTimeout,
 			}
 		} else {
 			transport = &http2.Transport{
@@ -215,9 +240,27 @@ func newClientManager(url *common.URL) (*clientManager, error) {
 				PingTimeout:     keepAliveTimeout,
 			}
 		}
+	case constant.CallHTTP3:
+		if !tlsFlag {
+			return nil, fmt.Errorf("TRIPLE http3 client must have TLS config, but TLS config is nil")
+		}
+
+		// TODO: Enrich the http3 transport config for triple protocol.
+		transport = &http3.Transport{
+			TLSClientConfig: cfg,
+			QUICConfig: &quic.Config{
+				// ref: https://quic-go.net/docs/quic/connection/#keeping-a-connection-alive
+				KeepAlivePeriod: keepAliveInterval,
+				// ref: https://quic-go.net/docs/quic/connection/#idle-timeout
+				MaxIdleTimeout: keepAliveTimeout,
+			},
+		}
+
+		logger.Infof("Triple http3 client transport init successfully")
 	default:
-		panic(fmt.Sprintf("Unsupported callType: %s", callType))
+		return nil, fmt.Errorf("unsupported http protocol: %s", callProtocol)
 	}
+
 	httpClient := &http.Client{
 		Transport: transport,
 	}
@@ -230,6 +273,7 @@ func newClientManager(url *common.URL) (*clientManager, error) {
 	} else {
 		baseTriURL = httpPrefix + baseTriURL
 	}
+
 	triClients := make(map[string]*tri.Client)
 
 	if len(url.Methods) != 0 {
@@ -268,7 +312,7 @@ func newClientManager(url *common.URL) (*clientManager, error) {
 	}, nil
 }
 
-func genKeepAliveOpts(url *common.URL) ([]tri.ClientOption, time.Duration, time.Duration, error) {
+func genKeepAliveOptions(url *common.URL, tripleConf *global.TripleConfig) ([]tri.ClientOption, time.Duration, time.Duration, error) {
 	var cliKeepAliveOpts []tri.ClientOption
 
 	// set max send and recv msg size
@@ -289,26 +333,22 @@ func genKeepAliveOpts(url *common.URL) ([]tri.ClientOption, time.Duration, time.
 	keepAliveInterval := url.GetParamDuration(constant.KeepAliveInterval, constant.DefaultKeepAliveInterval)
 	keepAliveTimeout := url.GetParamDuration(constant.KeepAliveTimeout, constant.DefaultKeepAliveTimeout)
 
-	tripleConfRaw, ok := url.GetAttribute(constant.TripleConfigKey)
-	if ok {
-		var parseErr error
-		tripleConf := tripleConfRaw.(*global.TripleConfig)
+	if tripleConf == nil {
+		return cliKeepAliveOpts, keepAliveInterval, keepAliveTimeout, nil
+	}
 
-		if tripleConf == nil {
-			return cliKeepAliveOpts, keepAliveInterval, keepAliveTimeout, nil
-		}
+	var parseErr error
 
-		if tripleConf.KeepAliveInterval != "" {
-			keepAliveInterval, parseErr = time.ParseDuration(tripleConf.KeepAliveInterval)
-			if parseErr != nil {
-				return nil, 0, 0, parseErr
-			}
+	if tripleConf.KeepAliveInterval != "" {
+		keepAliveInterval, parseErr = time.ParseDuration(tripleConf.KeepAliveInterval)
+		if parseErr != nil {
+			return nil, 0, 0, parseErr
 		}
-		if tripleConf.KeepAliveTimeout != "" {
-			keepAliveTimeout, parseErr = time.ParseDuration(tripleConf.KeepAliveTimeout)
-			if parseErr != nil {
-				return nil, 0, 0, parseErr
-			}
+	}
+	if tripleConf.KeepAliveTimeout != "" {
+		keepAliveTimeout, parseErr = time.ParseDuration(tripleConf.KeepAliveTimeout)
+		if parseErr != nil {
+			return nil, 0, 0, parseErr
 		}
 	}
 
diff --git a/protocol/triple/options.go b/protocol/triple/options.go
index b1b634a52..a83164dce 100644
--- a/protocol/triple/options.go
+++ b/protocol/triple/options.go
@@ -92,3 +92,16 @@ func WithMaxServerRecvMsgSize(size string) Option {
 		opts.Triple.MaxServerRecvMsgSize = size
 	}
 }
+
+// Http3Enable enables HTTP/3 support for the Triple protocol.
+// It sets the corresponding configuration to enable HTTP/3.
+//
+// # Experimental
+//
+// NOTICE: This API is EXPERIMENTAL and may be changed or removed in
+// a later release.
+func Http3Enable() Option {
+	return func(opts *Options) {
+		opts.Triple.Http3.Enable = true
+	}
+}
diff --git a/protocol/triple/server.go b/protocol/triple/server.go
index 50be3ab93..076b15210 100644
--- a/protocol/triple/server.go
+++ b/protocol/triple/server.go
@@ -19,6 +19,7 @@ package triple
 
 import (
 	"context"
+	"crypto/tls"
 	"fmt"
 	"net/http"
 	"reflect"
@@ -71,12 +72,28 @@ func NewServer(cfg *global.TripleConfig) *Server {
 
 // Start TRIPLE server
 func (s *Server) Start(invoker base.Invoker, info *common.ServiceInfo) {
-	URL := invoker.GetURL()
-	addr := URL.Location
+	url := invoker.GetURL()
+	addr := url.Location
+
+	var tripleConf *global.TripleConfig
+
+	tripleConfRaw, ok := url.GetAttribute(constant.TripleConfigKey)
+	if ok {
+		tripleConf = tripleConfRaw.(*global.TripleConfig)
+	}
+
+	var callProtocol string
+	if tripleConf != nil && tripleConf.Http3 != nil && tripleConf.Http3.Enable {
+		callProtocol = constant.CallHTTP3
+	} else {
+		// HTTP default type is HTTP/2.
+		callProtocol = constant.CallHTTP2
+	}
+
 	// initialize tri.Server
 	s.triServer = tri.NewServer(addr)
 
-	serialization := URL.GetParam(constant.SerializationKey, constant.ProtobufSerialization)
+	serialization := url.GetParam(constant.SerializationKey, constant.ProtobufSerialization)
 	switch serialization {
 	case constant.ProtobufSerialization:
 	case constant.JSONSerialization:
@@ -89,41 +106,44 @@ func (s *Server) Start(invoker base.Invoker, info *common.ServiceInfo) {
 
 	// TODO: move tls config to handleService
 
-	var tlsConf *global.TLSConfig
+	var globalTlsConf *global.TLSConfig
+	var tlsConf *tls.Config
+	var err error
 
 	// handle tls
-	tlsConfRaw, ok := URL.GetAttribute(constant.TLSConfigKey)
+	tlsConfRaw, ok := url.GetAttribute(constant.TLSConfigKey)
 	if ok {
-		tlsConf, ok = tlsConfRaw.(*global.TLSConfig)
+		globalTlsConf, ok = tlsConfRaw.(*global.TLSConfig)
 		if !ok {
 			logger.Errorf("TRIPLE Server initialized the TLSConfig configuration failed")
 			return
 		}
 	}
-	if dubbotls.IsServerTLSValid(tlsConf) {
-		cfg, err := dubbotls.GetServerTlSConfig(tlsConf)
+	if dubbotls.IsServerTLSValid(globalTlsConf) {
+		tlsConf, err = dubbotls.GetServerTlSConfig(globalTlsConf)
 		if err != nil {
 			logger.Errorf("TRIPLE Server initialized the TLSConfig configuration failed. err: %v", err)
 			return
 		}
-		s.triServer.SetTLSConfig(cfg)
 		logger.Infof("TRIPLE Server initialized the TLSConfig configuration")
 	}
 
 	// IDLMode means that this will only be set when
 	// the new triple is started in non-IDL mode.
 	// TODO: remove IDLMode when config package is removed
-	IDLMode := URL.GetParam(constant.IDLMode, "")
+	IDLMode := url.GetParam(constant.IDLMode, "")
 
 	var service common.RPCService
 	if IDLMode == constant.NONIDL {
-		service, _ = URL.GetAttribute(constant.RpcServiceKey)
+		service, _ = url.GetAttribute(constant.RpcServiceKey)
 	}
 
-	hanOpts := getHanOpts(URL)
+	hanOpts := getHanOpts(url, tripleConf)
+
 	//Set expected codec name from serviceinfo
 	hanOpts = append(hanOpts, tri.WithExpectedCodecName(serialization))
-	intfName := URL.Interface()
+
+	intfName := url.Interface()
 	if info != nil {
 		// new triple idl mode
 		s.handleServiceWithInfo(intfName, invoker, info, hanOpts...)
@@ -135,12 +155,12 @@ func (s *Server) Start(invoker base.Invoker, info *common.ServiceInfo) {
 		s.saveServiceInfo(intfName, reflectInfo)
 	} else {
 		// old triple idl mode and old triple non-idl mode
-		s.compatHandleService(intfName, URL.Group(), URL.Version(), hanOpts...)
+		s.compatHandleService(intfName, url.Group(), url.Version(), hanOpts...)
 	}
 	internal.ReflectionRegister(s)
 
 	go func() {
-		if runErr := s.triServer.Run(); runErr != nil {
+		if runErr := s.triServer.Run(callProtocol, tlsConf); runErr != nil {
 			logger.Errorf("server serve failed with err: %v", runErr)
 		}
 	}()
@@ -159,7 +179,7 @@ func (s *Server) RefreshService(invoker base.Invoker, info *common.ServiceInfo)
 	default:
 		panic(fmt.Sprintf("Unsupported serialization: %s", serialization))
 	}
-	hanOpts := getHanOpts(URL)
+	hanOpts := getHanOpts(URL, s.cfg)
 	//Set expected codec name from serviceinfo
 	hanOpts = append(hanOpts, tri.WithExpectedCodecName(serialization))
 	intfName := URL.Interface()
@@ -171,14 +191,13 @@ func (s *Server) RefreshService(invoker base.Invoker, info *common.ServiceInfo)
 	}
 }
 
-func getHanOpts(url *common.URL) (hanOpts []tri.HandlerOption) {
+func getHanOpts(url *common.URL, tripleConf *global.TripleConfig) (hanOpts []tri.HandlerOption) {
 	group := url.GetParam(constant.GroupKey, "")
 	version := url.GetParam(constant.VersionKey, "")
 	hanOpts = append(hanOpts, tri.WithGroup(group), tri.WithVersion(version))
 
 	// Deprecated:use TripleConfig
 	// TODO: remove MaxServerSendMsgSize and MaxServerRecvMsgSize when version 4.0.0
-	var err error
 	maxServerRecvMsgSize := constant.DefaultMaxServerRecvMsgSize
 	if recvMsgSize, convertErr := humanize.ParseBytes(url.GetParam(constant.MaxServerRecvMsgSize, "")); convertErr == nil && recvMsgSize != 0 {
 		maxServerRecvMsgSize = int(recvMsgSize)
@@ -188,24 +207,17 @@ func getHanOpts(url *common.URL) (hanOpts []tri.HandlerOption) {
 	// Deprecated:use TripleConfig
 	// TODO: remove MaxServerSendMsgSize and MaxServerRecvMsgSize when version 4.0.0
 	maxServerSendMsgSize := constant.DefaultMaxServerSendMsgSize
-	if sendMsgSize, convertErr := humanize.ParseBytes(url.GetParam(constant.MaxServerSendMsgSize, "")); err == convertErr && sendMsgSize != 0 {
+	if sendMsgSize, convertErr := humanize.ParseBytes(url.GetParam(constant.MaxServerSendMsgSize, "")); convertErr == nil && sendMsgSize != 0 {
 		maxServerSendMsgSize = int(sendMsgSize)
 	}
 	hanOpts = append(hanOpts, tri.WithSendMaxBytes(maxServerSendMsgSize))
 
-	var tripleConf *global.TripleConfig
-
-	tripleConfRaw, ok := url.GetAttribute(constant.TripleConfigKey)
-	if ok {
-		tripleConf = tripleConfRaw.(*global.TripleConfig)
-	}
-
 	if tripleConf == nil {
 		return hanOpts
 	}
 
 	if tripleConf.MaxServerRecvMsgSize != "" {
-		logger.Warnf("MaxServerRecvMsgSize: %v", tripleConf.MaxServerRecvMsgSize)
+		logger.Debugf("MaxServerRecvMsgSize: %v", tripleConf.MaxServerRecvMsgSize)
 		if recvMsgSize, convertErr := humanize.ParseBytes(tripleConf.MaxServerRecvMsgSize); convertErr == nil && recvMsgSize != 0 {
 			maxServerRecvMsgSize = int(recvMsgSize)
 		}
@@ -213,8 +225,8 @@ func getHanOpts(url *common.URL) (hanOpts []tri.HandlerOption) {
 	}
 
 	if tripleConf.MaxServerSendMsgSize != "" {
-		logger.Warnf("MaxServerSendMsgSize: %v", tripleConf.MaxServerSendMsgSize)
-		if sendMsgSize, convertErr := humanize.ParseBytes(tripleConf.MaxServerSendMsgSize); err == convertErr && sendMsgSize != 0 {
+		logger.Debugf("MaxServerSendMsgSize: %v", tripleConf.MaxServerSendMsgSize)
+		if sendMsgSize, convertErr := humanize.ParseBytes(tripleConf.MaxServerSendMsgSize); convertErr == nil && sendMsgSize != 0 {
 			maxServerSendMsgSize = int(sendMsgSize)
 		}
 		hanOpts = append(hanOpts, tri.WithSendMaxBytes(maxServerSendMsgSize))
diff --git a/protocol/triple/triple_protocol/server.go b/protocol/triple/triple_protocol/server.go
index 3efbe73ce..a7089220f 100644
--- a/protocol/triple/triple_protocol/server.go
+++ b/protocol/triple/triple_protocol/server.go
@@ -20,7 +20,10 @@ package triple_protocol
 import (
 	"context"
 	"crypto/tls"
+	"errors"
+	"fmt"
 	"net/http"
+	"strings"
 	"sync"
 )
 
@@ -31,13 +34,22 @@ import (
 
 	"golang.org/x/net/http2"
 	"golang.org/x/net/http2/h2c"
+
+	"github.com/quic-go/quic-go"
+	"github.com/quic-go/quic-go/http3"
+)
+
+import (
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
 )
 
 type Server struct {
 	mu       sync.Mutex
+	addr     string
 	mux      *http.ServeMux
 	handlers map[string]*Handler
 	httpSrv  *http.Server
+	http3Srv *http3.Server
 }
 
 func (s *Server) RegisterUnaryHandler(
@@ -160,44 +172,158 @@ func (s *Server) RegisterCompatStreamHandler(
 	return nil
 }
 
-func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	handler, pattern := s.mux.Handler(r)
-	if pattern == "" {
-		logger.Warnf("404: didn't register this method - %s\n", r.URL.Path)
+func (s *Server) Run(callProtocol string, tlsConf *tls.Config) error {
+	// TODO: Refactor to support starting HTTP/2 and HTTP/3 servers simultaneously.
+	// The current switch logic is mutually exclusive. Future work should allow enabling
+	// both protocols, likely based on configuration, and run them concurrently.
+	switch callProtocol {
+	case constant.CallHTTP2:
+		return s.startHttp2(tlsConf)
+	case constant.CallHTTP3:
+		return s.startHttp3(tlsConf)
+	default:
+		return fmt.Errorf("unsupported protocol: %s, only http2 or http3 are supported", callProtocol)
 	}
-
-	handler.ServeHTTP(w, r)
 }
 
-func (s *Server) Run() error {
-	s.httpSrv.Handler = h2c.NewHandler(s, &http2.Server{})
+func (s *Server) startHttp2(tlsConf *tls.Config) error {
+	s.httpSrv = &http.Server{
+		Addr:      s.addr,
+		Handler:   h2c.NewHandler(s.mux, &http2.Server{}),
+		TLSConfig: tlsConf,
+	}
+
+	logger.Debugf("TRIPLE HTTP/2 Server starting on %v", s.addr)
 
 	var err error
-	if s.httpSrv.TLSConfig != nil {
-		// TODO: Maybe we should be able to find a better way to start TLS.
+
+	if tlsConf != nil {
 		err = s.httpSrv.ListenAndServeTLS("", "")
 	} else {
 		err = s.httpSrv.ListenAndServe()
 	}
+
 	return err
 }
 
-func (s *Server) SetTLSConfig(c *tls.Config) {
-	s.httpSrv.TLSConfig = c
+func (s *Server) startHttp3(tlsConf *tls.Config) error {
+	if tlsConf == nil {
+		return fmt.Errorf("TRIPLE HTTP/3 Server must have TLS config, but TLS config is nil")
+	}
+
+	s.http3Srv = &http3.Server{
+		Addr:    s.addr,
+		Handler: s.mux,
+		// Adapt and enhance a generic tls.Config object into a configuration
+		// specifically for HTTP/3 services.
+		// ref: https://quic-go.net/docs/http3/server/#setting-up-a-http3server
+		TLSConfig: http3.ConfigureTLSConfig(tlsConf),
+		// TODO: Detailed QUIC configuration.
+		QUICConfig: &quic.Config{},
+	}
+
+	logger.Debugf("TRIPLE HTTP/3 Server starting on %v", s.addr)
+
+	return s.http3Srv.ListenAndServe()
 }
 
+// Stop the Triple server for both HTTP/2 and HTTP/3.
+// Because stop is very fast, there is no need to parallelize stop.
 func (s *Server) Stop() error {
-	return s.httpSrv.Close()
+	var errs []error
+
+	// stop HTTP server
+	if s.httpSrv != nil {
+		if err := s.httpSrv.Close(); err != nil {
+			errs = append(errs, fmt.Errorf("http server close failed: %w", err))
+		}
+	}
+
+	// stop HTTP/3 server
+	if s.http3Srv != nil {
+		if err := s.http3Srv.Close(); err != nil {
+			errs = append(errs, fmt.Errorf("http3 server close failed: %w", err))
+		}
+	}
+
+	switch len(errs) {
+	case 0:
+		return nil
+	case 1:
+		return errs[0]
+	default:
+		var sb strings.Builder
+		sb.WriteString("multiple errors occurred during stop:")
+		for _, err := range errs {
+			// Newline and indent for easier reading
+			sb.WriteString("\n\t- ")
+			sb.WriteString(err.Error())
+		}
+		return errors.New(sb.String())
+	}
 }
 
+// Gracefulstop shutdown the Triple server for both HTTP/2 and HTTP/3 gracefully.
+// Because graceful shutdown is slow, I adopted concurrent processing.
 func (s *Server) GracefulStop(ctx context.Context) error {
-	return s.httpSrv.Shutdown(ctx)
+	var (
+		wg      sync.WaitGroup
+		errChan = make(chan error, 2)
+	)
+
+	// shutdown HTTP server
+	if s.httpSrv != nil {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			if err := s.httpSrv.Shutdown(ctx); err != nil {
+				errChan <- fmt.Errorf("http server shutdown failed: %w", err)
+			}
+		}()
+	}
+
+	// shutdown HTTP/3 server
+	if s.http3Srv != nil {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			if err := s.http3Srv.Shutdown(ctx); err != nil {
+				errChan <- fmt.Errorf("http3 server shutdown failed: %w", err)
+			}
+		}()
+	}
+
+	wg.Wait()
+	close(errChan)
+
+	// Error Collection and Handling.
+	// Collect all errors into a slice.
+	var errs []error
+	for err := range errChan {
+		errs = append(errs, err)
+	}
+
+	switch len(errs) {
+	case 0:
+		return nil
+	case 1:
+		return errs[0]
+	default:
+		var sb strings.Builder
+		sb.WriteString("multiple errors occurred during graceful stop:")
+		for _, err := range errs {
+			// Newline and indent for easier reading
+			sb.WriteString("\n\t- ")
+			sb.WriteString(err.Error())
+		}
+		return errors.New(sb.String())
+	}
 }
 
 func NewServer(addr string) *Server {
 	return &Server{
 		mux:      http.NewServeMux(),
+		addr:     addr,
 		handlers: make(map[string]*Handler),
-		httpSrv:  &http.Server{Addr: addr},
 	}
 }