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 <[email protected]>
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},
        }
 }

Reply via email to