Просмотр исходного кода

BurstObservatory: add option to set http method for burst check (#4835)

* feat: add options to set method for burst check.

* chore: gen proto.

* chore: change protoc-gen-go to latest.

* revert

---------

Co-authored-by: 风扇滑翔翼 <[email protected]>
Jesus 11 месяцев назад
Родитель
Сommit
27742da2c6

+ 13 - 2
app/observatory/burst/config.pb.go

@@ -90,6 +90,8 @@ type HealthPingConfig struct {
 	SamplingCount int32 `protobuf:"varint,4,opt,name=samplingCount,proto3" json:"samplingCount,omitempty"`
 	// ping timeout, int64 values of time.Duration
 	Timeout int64 `protobuf:"varint,5,opt,name=timeout,proto3" json:"timeout,omitempty"`
+	// http method to make request
+	HttpMethod string `protobuf:"bytes,6,opt,name=httpMethod,proto3" json:"httpMethod,omitempty"`
 }
 
 func (x *HealthPingConfig) Reset() {
@@ -157,6 +159,13 @@ func (x *HealthPingConfig) GetTimeout() int64 {
 	return 0
 }
 
+func (x *HealthPingConfig) GetHttpMethod() string {
+	if x != nil {
+		return x.HttpMethod
+	}
+	return ""
+}
+
 var File_app_observatory_burst_config_proto protoreflect.FileDescriptor
 
 var file_app_observatory_burst_config_proto_rawDesc = []byte{
@@ -173,7 +182,7 @@ var file_app_observatory_burst_config_proto_rawDesc = []byte{
 	0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x62, 0x75, 0x72,
 	0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
 	0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
-	0xb4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
+	0xd4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
 	0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
 	0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69,
 	0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
@@ -184,7 +193,9 @@ var file_app_observatory_burst_config_proto_rawDesc = []byte{
 	0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73,
 	0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07,
 	0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74,
-	0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
+	0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x4d, 0x65,
+	0x74, 0x68, 0x6f, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x68, 0x74, 0x74, 0x70,
+	0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
 	0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
 	0x72, 0x79, 0x2e, 0x62, 0x75, 0x72, 0x73, 0x74, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68,
 	0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,

+ 3 - 0
app/observatory/burst/config.proto

@@ -26,4 +26,7 @@ message HealthPingConfig {
   int32 samplingCount = 4;
   // ping timeout, int64 values of time.Duration
   int64 timeout = 5;
+  // http method to make request
+  string httpMethod = 6;
+
 }

+ 12 - 2
app/observatory/burst/healthping.go

@@ -19,6 +19,7 @@ type HealthPingSettings struct {
 	Interval      time.Duration `json:"interval"`
 	SamplingCount int           `json:"sampling"`
 	Timeout       time.Duration `json:"timeout"`
+	HttpMethod    string        `json:"httpMethod"`
 }
 
 // HealthPing is the health checker for balancers
@@ -37,12 +38,21 @@ type HealthPing struct {
 func NewHealthPing(ctx context.Context, dispatcher routing.Dispatcher, config *HealthPingConfig) *HealthPing {
 	settings := &HealthPingSettings{}
 	if config != nil {
+
+		var httpMethod string
+		if config.HttpMethod == "" {
+			httpMethod = "HEAD"
+		} else {
+			httpMethod = strings.TrimSpace(config.HttpMethod)
+		}
+
 		settings = &HealthPingSettings{
 			Connectivity:  strings.TrimSpace(config.Connectivity),
 			Destination:   strings.TrimSpace(config.Destination),
 			Interval:      time.Duration(config.Interval),
 			SamplingCount: int(config.SamplingCount),
 			Timeout:       time.Duration(config.Timeout),
+			HttpMethod:    httpMethod,
 		}
 	}
 	if settings.Destination == "" {
@@ -164,7 +174,7 @@ func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int)
 			}
 			time.AfterFunc(delay, func() {
 				errors.LogDebug(h.ctx, "checking ", handler)
-				delay, err := client.MeasureDelay()
+				delay, err := client.MeasureDelay(h.Settings.HttpMethod)
 				if err == nil {
 					ch <- &rtt{
 						handler: handler,
@@ -251,7 +261,7 @@ func (h *HealthPing) checkConnectivity() bool {
 		h.Settings.Connectivity,
 		h.Settings.Timeout,
 	)
-	if _, err := tester.MeasureDelay(); err != nil {
+	if _, err := tester.MeasureDelay(h.Settings.HttpMethod); err != nil {
 		return false
 	}
 	return true

+ 12 - 3
app/observatory/burst/ping.go

@@ -2,6 +2,7 @@ package burst
 
 import (
 	"context"
+	"io"
 	"net/http"
 	"time"
 
@@ -51,20 +52,28 @@ func newHTTPClient(ctxv context.Context, dispatcher routing.Dispatcher, handler
 }
 
 // MeasureDelay returns the delay time of the request to dest
-func (s *pingClient) MeasureDelay() (time.Duration, error) {
+func (s *pingClient) MeasureDelay(httpMethod string) (time.Duration, error) {
 	if s.httpClient == nil {
 		panic("pingClient not initialized")
 	}
-	req, err := http.NewRequest(http.MethodHead, s.destination, nil)
+
+	req, err := http.NewRequest(httpMethod, s.destination, nil)
 	if err != nil {
 		return rttFailed, err
 	}
+
 	start := time.Now()
 	resp, err := s.httpClient.Do(req)
 	if err != nil {
 		return rttFailed, err
 	}
-	// don't wait for body
+	if httpMethod == http.MethodGet {
+		_, err = io.Copy(io.Discard, resp.Body)
+		if err != nil {
+			return rttFailed, err
+		}
+	}
 	resp.Body.Close()
+
 	return time.Since(start), nil
 }

+ 9 - 0
infra/conf/router_strategy.go

@@ -2,6 +2,7 @@ package conf
 
 import (
 	"google.golang.org/protobuf/proto"
+	"strings"
 
 	"github.com/xtls/xray-core/app/observatory/burst"
 	"github.com/xtls/xray-core/app/router"
@@ -51,15 +52,23 @@ type healthCheckSettings struct {
 	Interval      duration.Duration `json:"interval"`
 	SamplingCount int               `json:"sampling"`
 	Timeout       duration.Duration `json:"timeout"`
+	HttpMethod    string            `json:"httpMethod"`
 }
 
 func (h healthCheckSettings) Build() (proto.Message, error) {
+	var httpMethod string
+	if h.HttpMethod == "" {
+		httpMethod = "HEAD"
+	} else {
+		httpMethod = strings.TrimSpace(h.HttpMethod)
+	}
 	return &burst.HealthPingConfig{
 		Destination:   h.Destination,
 		Connectivity:  h.Connectivity,
 		Interval:      int64(h.Interval),
 		Timeout:       int64(h.Timeout),
 		SamplingCount: int32(h.SamplingCount),
+		HttpMethod:    httpMethod,
 	}, nil
 }