diff --git a/bfe_balance/backend/bfe_backend.go b/bfe_balance/backend/bfe_backend.go index 1cea20641..e5549ae82 100644 --- a/bfe_balance/backend/bfe_backend.go +++ b/bfe_balance/backend/bfe_backend.go @@ -18,10 +18,10 @@ package backend import ( "fmt" + "net" + "strconv" "sync" -) -import ( "github.com/bfenetworks/bfe/bfe_config/bfe_cluster_conf/cluster_table_conf" "github.com/bfenetworks/bfe/bfe_route/bfe_cluster" ) @@ -54,6 +54,35 @@ func NewBfeBackend() *BfeBackend { return backend } +func (back *BfeBackend) InitSimpleByAddrinfo(subClusterName string, name string, addrinfo string) { + back.Name = name + + // parse addrinfo to addr and port + host, portStr, err := net.SplitHostPort(addrinfo) + if err != nil { + back.Addr = addrinfo + back.Port = 0 + } else { + back.Addr = host + if p, err2 := strconv.Atoi(portStr); err2 == nil { + back.Port = p + } else { + back.Port = 0 + } + } + back.AddrInfo = addrinfo + back.SubCluster = subClusterName +} + +func NewBfeBackendByAddrinfo(subClusterName string, name string, addrinfo string) *BfeBackend { + backend := new(BfeBackend) + backend.avail = true + + backend.InitSimpleByAddrinfo(subClusterName, name, addrinfo) + + return backend +} + // Init initializes BfeBackend with BackendConf func (back *BfeBackend) Init(subCluster string, conf *cluster_table_conf.BackendConf) { back.Name = *conf.Name diff --git a/bfe_balance/bal_gslb/bal_gslb.go b/bfe_balance/bal_gslb/bal_gslb.go index 32d11c73e..0a2df778c 100644 --- a/bfe_balance/bal_gslb/bal_gslb.go +++ b/bfe_balance/bal_gslb/bal_gslb.go @@ -22,27 +22,27 @@ import ( "math/rand" "net" "sort" + "strings" "sync" "time" -) -import ( "github.com/baidu/go-lib/log" "github.com/baidu/go-lib/web-monitor/metrics" -) -import ( bal_backend "github.com/bfenetworks/bfe/bfe_balance/backend" "github.com/bfenetworks/bfe/bfe_balance/bal_slb" "github.com/bfenetworks/bfe/bfe_basic" "github.com/bfenetworks/bfe/bfe_config/bfe_cluster_conf/cluster_conf" "github.com/bfenetworks/bfe/bfe_config/bfe_cluster_conf/cluster_table_conf" "github.com/bfenetworks/bfe/bfe_config/bfe_cluster_conf/gslb_conf" + "github.com/bfenetworks/bfe/bfe_util/epp" + extprocv3 "github.com/envoyproxy/go-control-plane/envoy/service/ext_proc/v3" ) const ( DefaultRetryMax = 3 // default max retries in assigned sub cluster DefaultCrossRetryMax = 1 // default max retries in other sub cluster, if retries in assigned sub cluster fail + REQ_CTX_EPP = "epp_ctx" ) type BalanceGslb struct { @@ -59,6 +59,13 @@ type BalanceGslb struct { crossRetry int // max retries in other sub cluster, if all retry within assigned sub cluster fail hashConf cluster_conf.HashConf // gslb hash conf BalanceMode string // balanceMode, WRR or WLC, defined in cluster_conf + + // EPP related + eppClient epp.EppGrpcClient + eppAddrs []string + eppConnTimeout time.Duration + eppCallRetry uint32 + eppConcurrency int } func NewBalanceGslb(name string) *BalanceGslb { @@ -87,6 +94,20 @@ func (bal *BalanceGslb) SetGslbBasic(gslbBasic cluster_conf.GslbBasicConf) { bal.BalanceMode = *gslbBasic.BalanceMode bal.lock.Unlock() + // close EPP client if any + bal.closeEPP() + + // init or close EPP client according to balance mode + if gslbBasic.BalanceMode != nil && strings.ToUpper(*gslbBasic.BalanceMode) == cluster_conf.BalanceModeEPP { + if gslbBasic.EPPAddr != nil && len(*gslbBasic.EPPAddr) > 0 { + if err := bal.initEPP(*gslbBasic.EPPAddr); err != nil { + log.Logger.Error("initEPP failed: %v", err) + } + } + } else { + // non-EPP mode, ensure EPP is closed + bal.closeEPP() + } } func (bal *BalanceGslb) SetSlowStart(backendConf cluster_conf.BackendBasic) { @@ -99,6 +120,163 @@ func (bal *BalanceGslb) SetSlowStart(backendConf cluster_conf.BackendBasic) { bal.lock.Unlock() } +// initEPP initializes or refreshes EPP client with given addresses. +func (bal *BalanceGslb) initEPP(addrs []string) error { + if len(addrs) == 0 { + bal.closeEPP() + return nil + } + + // if same as existing, do nothing + if len(bal.eppAddrs) == len(addrs) { + same := true + for i := range addrs { + if bal.eppAddrs[i] != addrs[i] { + same = false + break + } + } + if same { + return nil + } + } + + // build client via grpc_pool wrapper + // use default small timeouts/concurrency; tune as needed + // client, err := epp.NewClient(addrs, 100*time.Second, 2, 2) + client, err := epp.NewSimpleGrpcClient(addrs[0], 100*time.Second) + if err != nil { + return err + } + + // swap in new client + if bal.eppClient != nil { + bal.eppClient.Close() + } + bal.eppClient = client + bal.eppAddrs = append([]string(nil), addrs...) + return nil +} + +// closeEPP closes and clears EPP client if exists +func (bal *BalanceGslb) closeEPP() { + if bal.eppClient != nil { + bal.eppClient.Close() + bal.eppClient = nil + } + bal.eppAddrs = nil +} + +// chooseBackendFromEPP is a hook to call EPP service to get target backend address. +// Current implementation is a stub that returns empty result (meaning no decision). +// Implement actual gRPC call to EPP service here using bal.eppClient.Conn(). +func (bal *BalanceGslb) chooseBackendFromEPP(req *bfe_basic.Request) (string, *epp.EppClient, error) { + if bal.eppClient == nil { + return "", nil, fmt.Errorf("no epp client") + } + + conn := bal.eppClient.Conn() + if conn == nil { + return "", nil, fmt.Errorf("epp conn not ready") + } + + client, err := epp.NewEppClient(conn) + if err != nil { + return "", nil, err + } + + // build subset hint metadata if request provides backend subset (optional) + // For now, we only send minimal metadata and headers: host and path + // Build filter metadata: {"envoy.lb.subset_hint": {"x-gateway-destination-endpoint-subset": [..]}} + //filterMeta := map[string]*structpb.Struct{} + // no subset by default + //metadata := &corev3.Metadata{FilterMetadata: filterMeta} + + // construct ProcessingRequest with request_headers + // HttpHeaders requires HeaderMap; construct minimal representation using attributes map + hasBody := true + if req.OutRequest.ContentLength == 0 { + hasBody = false + } + + reqMsg := &extprocv3.ProcessingRequest{ + Request: &extprocv3.ProcessingRequest_RequestHeaders{ + RequestHeaders: epp.BuildEnvoyGRPCHeaders(req.OutRequest.Header, true, !hasBody), + }, + //MetadataContext: metadata, + } + + if err := client.Send(reqMsg); err != nil { + client.Close() + return "", nil, err + } + + if hasBody { + var body []byte + bodyAccessor, _ := req.OutRequest.GetBodyAccessor() + if bodyAccessor != nil { + body, _ = bodyAccessor.GetBytes() + } + + reqMsg := &extprocv3.ProcessingRequest{ + Request: &extprocv3.ProcessingRequest_RequestBody{ + RequestBody: &extprocv3.HttpBody{ + Body: body, + //Body: httpReq.Body, + EndOfStream: true, + }, + }, + //MetadataContext: metadata, + } + + if err := client.Send(reqMsg); err != nil { + client.Close() + return "", nil, err + } + } + + // receive response + resp, err := client.Recv() + if err != nil { + client.Close() + return "", nil, err + } + + var addrinfo string + // Try to inspect dynamic_metadata + if md := resp.GetDynamicMetadata(); md != nil { + if v, ok := md.Fields["envoy.lb"]; ok { + // try to get x-gateway-destination-endpoint + if m := v.GetStructValue(); m != nil { + if val, found := m.Fields["x-gateway-destination-endpoint"]; found { + if s := val.GetStringValue(); s != "" { + // may be comma separated list, pick first + parts := strings.Split(s, ",") + addrinfo = strings.TrimSpace(parts[0]) + } + } + } + } + } + + if hasBody && resp.Response != nil && resp.GetRequestHeaders() != nil { + // receive response for request body + resp, err = client.Recv() + // the response should be resp.GetRequestBody() + if err != nil { + client.Close() + return "", nil, err + } + } + + if addrinfo != "" { + return addrinfo, client, nil + } + + client.Close() + return "", nil, fmt.Errorf("no endpoint from epp") +} + // Init initializes gslb cluster with config func (bal *BalanceGslb) Init(gslbConf gslb_conf.GslbClusterConf) error { totalWeight := 0 @@ -312,6 +490,44 @@ func getHashKeyByHeader(req *bfe_basic.Request, header string) []byte { return nil } +func (bal *BalanceGslb) BalanceEpp(req *bfe_basic.Request) (*bal_backend.BfeBackend, error) { + var backend *bal_backend.BfeBackend + var err error + + bal.lock.Lock() + defer bal.lock.Unlock() + + // still in-cluster selection + if req.RetryTime > bal.retryMax { + // for epp only check in-cluster. + state.ErrBkRetryTooMany.Inc(1) + // Note: not modify req.ErrCode to just record last error + return nil, bfe_basic.ErrBkRetryTooMany + } + + // If BalanceMode == EPP, try to get backend from EPP service first + addrinfo, eppClient, err := bal.chooseBackendFromEPP(req) + if err == nil && addrinfo != "" { + req.SetContext(REQ_CTX_EPP, eppClient) + // try to find backend in subclusters + for _, sub := range bal.subClusters { + if sub == nil { + continue + } + bk, berr := sub.backends.LookUpBackend(addrinfo) + if berr == nil && bk != nil { + req.Backend.SubclusterName = sub.Name + return bk, nil + } + } + // not found: log and make a temporary backend + log.Logger.Info("EPP returned addr %s not found in local backends", addrinfo) + backend = bal_backend.NewBfeBackendByAddrinfo("EPP_temp", addrinfo, addrinfo) + return backend, nil + } + return nil, fmt.Errorf("EPP no decision") +} + // Balance selects a backend for given request. func (bal *BalanceGslb) Balance(req *bfe_basic.Request) (*bal_backend.BfeBackend, error) { var backend *bal_backend.BfeBackend diff --git a/bfe_balance/bal_slb/bal_rr.go b/bfe_balance/bal_slb/bal_rr.go index 507df0d46..7e6b4adf6 100644 --- a/bfe_balance/bal_slb/bal_rr.go +++ b/bfe_balance/bal_slb/bal_rr.go @@ -505,3 +505,17 @@ func GetHash(value []byte, base uint) int { return int(hash % uint64(base)) } + +// Look up backend with given addrInfo(ip:port) +func (brr *BalanceRR) LookUpBackend(addrInfo string) (*backend.BfeBackend, error) { + brr.Lock() + defer brr.Unlock() + + for _, backendRR := range brr.backends { + if backendRR.backend.AddrInfo == addrInfo && backendRR.backend.Avail() && backendRR.weight > 0 { + return backendRR.backend, nil + } + } + /* never come here */ + return nil, fmt.Errorf("rr_bal:LookUpBackend %s fail", addrInfo) +} diff --git a/bfe_config/bfe_cluster_conf/cluster_conf/cluster_conf_load.go b/bfe_config/bfe_cluster_conf/cluster_conf/cluster_conf_load.go index ba7351328..c9458ebd0 100644 --- a/bfe_config/bfe_cluster_conf/cluster_conf/cluster_conf_load.go +++ b/bfe_config/bfe_cluster_conf/cluster_conf/cluster_conf_load.go @@ -59,6 +59,7 @@ const ( const ( BalanceModeWrr = "WRR" // weighted round robin BalanceModeWlc = "WLC" // weighted least connection + BalanceModeEPP = "EPP" // balance by epp ) const ( @@ -207,6 +208,7 @@ type GslbBasicConf struct { HashConf *HashConf BalanceMode *string // balanceMode, default WRR + EPPAddr *[]string // EPP address } // ClusterBasicConf is basic conf for cluster. @@ -558,6 +560,10 @@ func GslbBasicConfCheck(conf *GslbBasicConf) error { switch *conf.BalanceMode { case BalanceModeWrr: case BalanceModeWlc: + case BalanceModeEPP: + if conf.EPPAddr == nil || len(*conf.EPPAddr) == 0 { + return errors.New("EPPAddr is nil or empty") + } default: return fmt.Errorf("unsupported bal mode %s", *conf.BalanceMode) } diff --git a/bfe_server/reverseproxy.go b/bfe_server/reverseproxy.go index 83e28fb0e..4f95804ea 100644 --- a/bfe_server/reverseproxy.go +++ b/bfe_server/reverseproxy.go @@ -51,6 +51,7 @@ import ( "github.com/bfenetworks/bfe/bfe_route/bfe_cluster" "github.com/bfenetworks/bfe/bfe_spdy" "github.com/bfenetworks/bfe/bfe_util" + "github.com/bfenetworks/bfe/bfe_util/epp" ) // TrailerPrefix is a magic prefix for ResponseWriter.Header map keys @@ -333,11 +334,23 @@ func (p *ReverseProxy) clusterInvoke(srv *BfeServer, cluster *bfe_cluster.BfeClu // When request.RetryTime exceeds some value, srv.clusterTable.Lookup() // will return error. Here set a limit of 20, to avoid endless loop for i := 0; i < 20; i++ { - // get backend with cluster-name and request - clusterBackend, err = bal.Balance(request) - if err == bfe_basic.ErrBkCrossRetryBalance { - request.RetryTime += 1 - continue + clusterBackend = nil + err = nil + if bal.BalanceMode == cluster_conf.BalanceModeEPP { + eppClient := request.GetContext(bal_gslb.REQ_CTX_EPP) + if eppClient != nil { + eppClient.(*epp.EppClient).Close() + request.SetContext(bal_gslb.REQ_CTX_EPP, nil) + } + clusterBackend, err = bal.BalanceEpp(request) + } + if clusterBackend == nil { + // get backend with cluster-name and request + clusterBackend, err = bal.Balance(request) + if err == bfe_basic.ErrBkCrossRetryBalance { + request.RetryTime += 1 + continue + } } if err != nil { @@ -657,8 +670,8 @@ func (p *ReverseProxy) ServeHTTP(rw bfe_http.ResponseWriter, basicReq *bfe_basic var outreq *bfe_http.Request var serverConf *bfe_route.ServerDataConf var writeTimer *time.Timer - // var bf BufferFiller - // var ok bool + var ok bool + var eppClient *epp.EppClient req := basicReq.HttpRequest isRedirect := false @@ -891,6 +904,12 @@ func (p *ReverseProxy) ServeHTTP(rw bfe_http.ResponseWriter, basicReq *bfe_basic basicReq.SvrDataConf = nil if err != nil || res == nil { + eppclient := basicReq.GetContext(bal_gslb.REQ_CTX_EPP) + if eppclient != nil { + eppclient.(*epp.EppClient).Close() + basicReq.SetContext(bal_gslb.REQ_CTX_EPP, nil) + } + basicReq.Stat.ResponseStart = time.Now() basicReq.BfeStatusCode = bfe_http.StatusInternalServerError res = bfe_basic.CreateInternalSrvErrResp(basicReq) @@ -911,6 +930,14 @@ response_got: basicReq.IsSse = true } } + + eppClient, ok = basicReq.GetContext(bal_gslb.REQ_CTX_EPP).(*epp.EppClient) + if ok { + basicReq.SetContext(bal_gslb.REQ_CTX_EPP, nil) + eppClient.ProcRespHeader(res.Header, false) + b := epp.NewEppResponseBodyFilter(res.Body, eppClient) + res.Body = b + } // timeout for write response to client // Note: we use io.Copy() to read from backend and write to client. diff --git a/bfe_util/epp/epp_client.go b/bfe_util/epp/epp_client.go new file mode 100644 index 000000000..90da14360 --- /dev/null +++ b/bfe_util/epp/epp_client.go @@ -0,0 +1,245 @@ +// Copyright (c) 2026 The BFE Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package epp + +import ( + "context" + "crypto/tls" + "io" + "time" + + http "github.com/bfenetworks/bfe/bfe_http" + corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" + extprocv3 "github.com/envoyproxy/go-control-plane/envoy/service/ext_proc/v3" + pb "github.com/envoyproxy/go-control-plane/envoy/service/ext_proc/v3" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + + "github.com/baidu/go-lib/log" +) + +type EppGrpcClient interface { + Conn() *grpc.ClientConn + Close() +} + +type SimpleGrpcClient struct { + conn *grpc.ClientConn +} + +func NewSimpleGrpcClient(addr string, timeout time.Duration) (EppGrpcClient, error) { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + conn, err := grpc.DialContext(ctx, addr, + grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + InsecureSkipVerify: true, // skip cert verification for testing + })), + grpc.WithBlock(), + ) + if err != nil { + return nil, err + } + + return &SimpleGrpcClient{conn: conn}, nil +} + +func (c *SimpleGrpcClient) Conn() *grpc.ClientConn { + if c == nil { + return nil + } + return c.conn +} + +func (c *SimpleGrpcClient) Close() { + if c == nil || c.conn == nil { + return + } + c.conn.Close() + c.conn = nil +} + +type EppClient struct { + client extprocv3.ExternalProcessorClient + conn *grpc.ClientConn + ctx context.Context + cancel context.CancelFunc + stream extprocv3.ExternalProcessor_ProcessClient + datach chan []byte + donech chan struct{} +} + +func NewEppClient(conn *grpc.ClientConn) (*EppClient, error) { + eppClient := &EppClient{} + eppClient.client = extprocv3.NewExternalProcessorClient(conn) + eppClient.conn = conn + eppClient.ctx, eppClient.cancel = context.WithCancel(context.Background()) + + stream, err := eppClient.client.Process(eppClient.ctx) + if err != nil { + return nil, err + } + eppClient.stream = stream + + return eppClient, nil +} + +func (c *EppClient) Close() { + c.CloseRespBody() + + if c.donech != nil { + <-c.donech + } + c.cancel() +} + +func (c *EppClient) Send(req *extprocv3.ProcessingRequest) error { + return c.stream.Send(req) +} + +func (c *EppClient) Recv() (*extprocv3.ProcessingResponse, error) { + return c.stream.Recv() +} + +func (c *EppClient) ProcRespHeader(header http.Header, endofstream bool) { + req := &extprocv3.ProcessingRequest{ + Request: &extprocv3.ProcessingRequest_ResponseHeaders{ + ResponseHeaders: BuildEnvoyGRPCHeaders(header, false, endofstream), + }, + } + c.datach = make(chan []byte, 10) + c.donech = make(chan struct{}) + + go func() { + // defer c.Close() + defer close(c.donech) + + // send request + if err := c.Send(req); err != nil { + log.Logger.Warn("EppClient ProcRespHeader send error: %v", err) + return + } + // receive response + _, err := c.Recv() + if err != nil { + log.Logger.Warn("EppClient ProcRespHeader recv error: %v", err) + return + } + + for d := range c.datach { + // send data to EPP server + req := &extprocv3.ProcessingRequest{ + Request: &extprocv3.ProcessingRequest_ResponseBody{ + ResponseBody: &extprocv3.HttpBody{ + Body: d, + EndOfStream: false, + }, + }, + } + err := c.Send(req) + if err != nil { + // log error and return + log.Logger.Warn("EppResponseBodyFilter send body chunk error: %v", err) + return + } + } + // send end of stream + req := &extprocv3.ProcessingRequest{ + Request: &extprocv3.ProcessingRequest_ResponseBody{ + ResponseBody: &extprocv3.HttpBody{ + Body: []byte(""), + EndOfStream: true, + }, + }, + } + err = c.Send(req) + if err != nil { + // log error + log.Logger.Warn("EppResponseBodyFilter send end of stream error: %v", err) + return + } + // receive response from EPP server + _, err = c.Recv() + if err != nil { + // log error + log.Logger.Warn("EppResponseBodyFilter recv end of stream response error: %v", err) + return + } + }() +} + +func (c *EppClient) ProcRespBody(d []byte) { + // Non-blocking send - if channel is full, skip sending + select { + case c.datach <- d: + default: + // Channel is full, skip this data block + } +} + +func (c *EppClient) CloseRespBody() { + if c.datach == nil { + return + } + close(c.datach) +} + +func BuildEnvoyGRPCHeaders(header http.Header, rawValue bool, endofstream bool) *pb.HttpHeaders { + headerValues := make([]*corev3.HeaderValue, 0) + for key, value := range header { + header := &corev3.HeaderValue{Key: key} + if rawValue { + header.RawValue = []byte(value[0]) + } else { + header.Value = value[0] + } + headerValues = append(headerValues, header) + } + return &pb.HttpHeaders{ + Headers: &corev3.HeaderMap{ + Headers: headerValues, + }, + EndOfStream: endofstream, + } +} + +type EppResponseBodyFilter struct { + source io.ReadCloser + c *EppClient +} + +func NewEppResponseBodyFilter(source io.ReadCloser, c *EppClient) *EppResponseBodyFilter { + return &EppResponseBodyFilter{ + source: source, + c: c, + } +} + +func (f *EppResponseBodyFilter) Read(p []byte) (n int, err error) { + n, err = f.source.Read(p) + if n > 0 { + // Send a copy of the data to the channel to avoid data race + dataCopy := make([]byte, n) + copy(dataCopy, p[:n]) + f.c.ProcRespBody(dataCopy) + } + return n, err +} + +func (f *EppResponseBodyFilter) Close() error { + err := f.source.Close() + f.c.Close() + return err +} diff --git a/go.mod b/go.mod index 69d146ec6..e2d52b486 100644 --- a/go.mod +++ b/go.mod @@ -41,15 +41,21 @@ require ( require ( github.com/bfenetworks/proxy-wasm-go-host v0.0.0-20241202144118-62704e5df808 + github.com/envoyproxy/go-control-plane/envoy v1.32.3 github.com/go-jose/go-jose/v4 v4.0.5 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.6.0 github.com/tidwall/gjson v1.18.0 github.com/tidwall/sjson v1.2.5 ) require ( + github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 // indirect + github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + google.golang.org/protobuf v1.35.2 // indirect ) require ( @@ -74,7 +80,7 @@ require ( go.elastic.co/apm/module/apmhttp v1.7.2 // indirect go.elastic.co/fastjson v1.1.0 // indirect golang.org/x/text v0.21.0 // indirect - google.golang.org/grpc v1.56.3 // indirect + google.golang.org/grpc v1.67.1 gopkg.in/yaml.v3 v3.0.1 // indirect howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect diff --git a/go.sum b/go.sum index da085ac17..42e9539de 100644 --- a/go.sum +++ b/go.sum @@ -23,6 +23,8 @@ github.com/bfenetworks/bwi v0.1.2/go.mod h1:zCRIdSw521zVnNCM73qw/lZ9UknbRux9rk6U github.com/bfenetworks/proxy-wasm-go-host v0.0.0-20241202144118-62704e5df808 h1:v0ckUMaZJFe8XvoM9x3kn+lDtMfI9EvpFadiOiV/s8A= github.com/bfenetworks/proxy-wasm-go-host v0.0.0-20241202144118-62704e5df808/go.mod h1:VG3ZZ8Zg7dYkla2hHy9UsX0GLl/dgJYP4IxuPvoq+/U= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 h1:N+3sFI5GUjRKBi+i0TxYVST9h4Ie192jJWpHvthBBgg= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cucumber/godog v0.8.1 h1:lVb+X41I4YDreE+ibZ50bdXmySxgRviYFgKY6Aw4XE8= github.com/cucumber/godog v0.8.1/go.mod h1:vSh3r/lM+psC1BPXvdkSEuNjmXfpVqrMGYAElF6hxnA= @@ -37,6 +39,10 @@ github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6 github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane/envoy v1.32.3 h1:hVEaommgvzTjTd4xCaFd+kEQ2iYBtGxP6luyLrx6uOk= +github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE= +github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= +github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= @@ -57,8 +63,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= @@ -113,6 +119,8 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -229,10 +237,14 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= -google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=