mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-22 00:21:29 +00:00
Add h2 & gRPC health check
This commit is contained in:
parent
d45298a10d
commit
d9d04a230f
|
@ -7,10 +7,23 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type GRPCConfig struct {
|
type GRPCConfig struct {
|
||||||
ServiceName string `json:"serviceName"`
|
ServiceName string `json:"serviceName" `
|
||||||
MultiMode bool `json:"multiMode"`
|
MultiMode bool `json:"multiMode"`
|
||||||
|
IdleTimeout int32 `json:"idle_timeout"`
|
||||||
|
HealthCheckTimeout int32 `json:"health_check_timeout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g GRPCConfig) Build() (proto.Message, error) {
|
func (g *GRPCConfig) Build() (proto.Message, error) {
|
||||||
return &grpc.Config{ServiceName: g.ServiceName, MultiMode: g.MultiMode}, nil
|
if g.IdleTimeout <= 0 {
|
||||||
|
g.IdleTimeout = 0
|
||||||
|
}
|
||||||
|
if g.HealthCheckTimeout <= 0 {
|
||||||
|
g.HealthCheckTimeout = 0
|
||||||
|
}
|
||||||
|
return &grpc.Config{
|
||||||
|
ServiceName: g.ServiceName,
|
||||||
|
MultiMode: g.MultiMode,
|
||||||
|
IdleTimeout: g.IdleTimeout,
|
||||||
|
HealthCheckTimeout: g.HealthCheckTimeout,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,14 +179,24 @@ func (c *WebSocketConfig) Build() (proto.Message, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPConfig struct {
|
type HTTPConfig struct {
|
||||||
Host *StringList `json:"host"`
|
Host *StringList `json:"host"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
|
ReadIdleTimeout int32 `json:"read_idle_timeout"`
|
||||||
|
HealthCheckTimeout int32 `json:"health_check_timeout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build implements Buildable.
|
// Build implements Buildable.
|
||||||
func (c *HTTPConfig) Build() (proto.Message, error) {
|
func (c *HTTPConfig) Build() (proto.Message, error) {
|
||||||
|
if c.ReadIdleTimeout <= 0 {
|
||||||
|
c.ReadIdleTimeout = 0
|
||||||
|
}
|
||||||
|
if c.HealthCheckTimeout <= 0 {
|
||||||
|
c.HealthCheckTimeout = 0
|
||||||
|
}
|
||||||
config := &http.Config{
|
config := &http.Config{
|
||||||
Path: c.Path,
|
Path: c.Path,
|
||||||
|
IdleTimeout: c.ReadIdleTimeout,
|
||||||
|
HealthCheckTimeout: c.HealthCheckTimeout,
|
||||||
}
|
}
|
||||||
if c.Host != nil {
|
if c.Host != nil {
|
||||||
config.Host = []string(*c.Host)
|
config.Host = []string(*c.Host)
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.25.0
|
// protoc-gen-go v1.26.0
|
||||||
// protoc v3.15.6
|
// protoc v3.17.3
|
||||||
// source: transport/internet/grpc/config.proto
|
// source: transport/internet/grpc/config.proto
|
||||||
|
|
||||||
package grpc
|
package grpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
proto "github.com/golang/protobuf/proto"
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
|
@ -21,18 +20,16 @@ const (
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
|
||||||
// of the legacy proto package is being used.
|
|
||||||
const _ = proto.ProtoPackageIsVersion4
|
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"`
|
Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"`
|
||||||
ServiceName string `protobuf:"bytes,2,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"`
|
ServiceName string `protobuf:"bytes,2,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"`
|
||||||
MultiMode bool `protobuf:"varint,3,opt,name=multi_mode,json=multiMode,proto3" json:"multi_mode,omitempty"`
|
MultiMode bool `protobuf:"varint,3,opt,name=multi_mode,json=multiMode,proto3" json:"multi_mode,omitempty"`
|
||||||
|
IdleTimeout int32 `protobuf:"varint,4,opt,name=idle_timeout,json=idleTimeout,proto3" json:"idle_timeout,omitempty"`
|
||||||
|
HealthCheckTimeout int32 `protobuf:"varint,5,opt,name=health_check_timeout,json=healthCheckTimeout,proto3" json:"health_check_timeout,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
|
@ -88,6 +85,20 @@ func (x *Config) GetMultiMode() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetIdleTimeout() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.IdleTimeout
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetHealthCheckTimeout() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.HealthCheckTimeout
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
var File_transport_internet_grpc_config_proto protoreflect.FileDescriptor
|
var File_transport_internet_grpc_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_transport_internet_grpc_config_proto_rawDesc = []byte{
|
var file_transport_internet_grpc_config_proto_rawDesc = []byte{
|
||||||
|
@ -95,17 +106,22 @@ var file_transport_internet_grpc_config_proto_rawDesc = []byte{
|
||||||
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x25, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x25, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
|
||||||
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
||||||
0x67, 0x72, 0x70, 0x63, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x5e, 0x0a,
|
0x67, 0x72, 0x70, 0x63, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0xb3, 0x01,
|
||||||
0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18,
|
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c,
|
||||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||||
0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d,
|
0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12,
|
||||||
0x0a, 0x0a, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01,
|
0x1d, 0x0a, 0x0a, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20,
|
||||||
0x28, 0x08, 0x52, 0x09, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x6f, 0x64, 0x65, 0x42, 0x33, 0x5a,
|
0x01, 0x28, 0x08, 0x52, 0x09, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x21,
|
||||||
0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73,
|
0x0a, 0x0c, 0x69, 0x64, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x04,
|
||||||
0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73,
|
0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x69, 0x64, 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75,
|
||||||
0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x72,
|
0x74, 0x12, 0x30, 0x0a, 0x14, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x63, 0x68, 0x65, 0x63,
|
||||||
0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x6b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||||
|
0x12, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65,
|
||||||
|
0x6f, 0x75, 0x74, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||||
|
0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65,
|
||||||
|
0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72,
|
||||||
|
0x6e, 0x65, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -7,4 +7,6 @@ message Config {
|
||||||
string host = 1;
|
string host = 1;
|
||||||
string service_name = 2;
|
string service_name = 2;
|
||||||
bool multi_mode = 3;
|
bool multi_mode = 3;
|
||||||
|
int32 idle_timeout = 4;
|
||||||
|
int32 health_check_timeout = 5;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"google.golang.org/grpc/backoff"
|
"google.golang.org/grpc/backoff"
|
||||||
"google.golang.org/grpc/connectivity"
|
"google.golang.org/grpc/connectivity"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
|
"google.golang.org/grpc/keepalive"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
@ -35,8 +36,7 @@ func init() {
|
||||||
|
|
||||||
type dialerConf struct {
|
type dialerConf struct {
|
||||||
net.Destination
|
net.Destination
|
||||||
*internet.SocketConfig
|
*internet.MemoryStreamConfig
|
||||||
*tls.Config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -47,9 +47,7 @@ var (
|
||||||
func dialgRPC(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (net.Conn, error) {
|
func dialgRPC(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (net.Conn, error) {
|
||||||
grpcSettings := streamSettings.ProtocolSettings.(*Config)
|
grpcSettings := streamSettings.ProtocolSettings.(*Config)
|
||||||
|
|
||||||
tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
|
conn, err := getGrpcClient(ctx, dest, streamSettings)
|
||||||
|
|
||||||
conn, err := getGrpcClient(ctx, dest, tlsConfig, streamSettings.SocketSettings)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newError("Cannot dial gRPC").Base(err)
|
return nil, newError("Cannot dial gRPC").Base(err)
|
||||||
|
@ -72,33 +70,22 @@ func dialgRPC(ctx context.Context, dest net.Destination, streamSettings *interne
|
||||||
return encoding.NewHunkConn(grpcService, nil), nil
|
return encoding.NewHunkConn(grpcService, nil), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getGrpcClient(ctx context.Context, dest net.Destination, tlsConfig *tls.Config, sockopt *internet.SocketConfig) (*grpc.ClientConn, error) {
|
func getGrpcClient(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (*grpc.ClientConn, error) {
|
||||||
globalDialerAccess.Lock()
|
globalDialerAccess.Lock()
|
||||||
defer globalDialerAccess.Unlock()
|
defer globalDialerAccess.Unlock()
|
||||||
|
|
||||||
if globalDialerMap == nil {
|
if globalDialerMap == nil {
|
||||||
globalDialerMap = make(map[dialerConf]*grpc.ClientConn)
|
globalDialerMap = make(map[dialerConf]*grpc.ClientConn)
|
||||||
}
|
}
|
||||||
|
tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
|
||||||
|
sockopt := streamSettings.SocketSettings
|
||||||
|
grpcSettings := streamSettings.ProtocolSettings.(*Config)
|
||||||
|
|
||||||
if client, found := globalDialerMap[dialerConf{dest, sockopt, tlsConfig}]; found && client.GetState() != connectivity.Shutdown {
|
if client, found := globalDialerMap[dialerConf{dest, streamSettings}]; found && client.GetState() != connectivity.Shutdown {
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
dialOption := grpc.WithInsecure()
|
var dialOptions = []grpc.DialOption{
|
||||||
|
|
||||||
if tlsConfig != nil {
|
|
||||||
dialOption = grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig.GetTLSConfig()))
|
|
||||||
}
|
|
||||||
|
|
||||||
var grpcDestHost string
|
|
||||||
if dest.Address.Family().IsDomain() {
|
|
||||||
grpcDestHost = dest.Address.Domain()
|
|
||||||
} else {
|
|
||||||
grpcDestHost = dest.Address.IP().String()
|
|
||||||
}
|
|
||||||
conn, err := grpc.Dial(
|
|
||||||
gonet.JoinHostPort(grpcDestHost, dest.Port.String()),
|
|
||||||
dialOption,
|
|
||||||
grpc.WithConnectParams(grpc.ConnectParams{
|
grpc.WithConnectParams(grpc.ConnectParams{
|
||||||
Backoff: backoff.Config{
|
Backoff: backoff.Config{
|
||||||
BaseDelay: 500 * time.Millisecond,
|
BaseDelay: 500 * time.Millisecond,
|
||||||
|
@ -132,7 +119,32 @@ func getGrpcClient(ctx context.Context, dest net.Destination, tlsConfig *tls.Con
|
||||||
address := net.ParseAddress(rawHost)
|
address := net.ParseAddress(rawHost)
|
||||||
return internet.DialSystem(gctx, net.TCPDestination(address, port), sockopt)
|
return internet.DialSystem(gctx, net.TCPDestination(address, port), sockopt)
|
||||||
}),
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
if tlsConfig != nil {
|
||||||
|
dialOptions = append(dialOptions, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig.GetTLSConfig())))
|
||||||
|
} else {
|
||||||
|
dialOptions = append(dialOptions, grpc.WithInsecure())
|
||||||
|
}
|
||||||
|
|
||||||
|
if grpcSettings.IdleTimeout > 0 || grpcSettings.HealthCheckTimeout > 0 {
|
||||||
|
dialOptions = append(dialOptions, grpc.WithKeepaliveParams(keepalive.ClientParameters{
|
||||||
|
Time: time.Second * time.Duration(grpcSettings.IdleTimeout),
|
||||||
|
Timeout: time.Second * time.Duration(grpcSettings.HealthCheckTimeout),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
var grpcDestHost string
|
||||||
|
if dest.Address.Family().IsDomain() {
|
||||||
|
grpcDestHost = dest.Address.Domain()
|
||||||
|
} else {
|
||||||
|
grpcDestHost = dest.Address.IP().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := grpc.Dial(
|
||||||
|
gonet.JoinHostPort(grpcDestHost, dest.Port.String()),
|
||||||
|
dialOptions...,
|
||||||
)
|
)
|
||||||
globalDialerMap[dialerConf{dest, sockopt, tlsConfig}] = conn
|
globalDialerMap[dialerConf{dest, streamSettings}] = conn
|
||||||
return conn, err
|
return conn, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.25.0
|
// protoc-gen-go v1.26.0
|
||||||
// protoc v3.14.0
|
// protoc v3.17.3
|
||||||
// source: transport/internet/http/config.proto
|
// source: transport/internet/http/config.proto
|
||||||
|
|
||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
proto "github.com/golang/protobuf/proto"
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
|
@ -21,17 +20,15 @@ const (
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
|
||||||
// of the legacy proto package is being used.
|
|
||||||
const _ = proto.ProtoPackageIsVersion4
|
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Host []string `protobuf:"bytes,1,rep,name=host,proto3" json:"host,omitempty"`
|
Host []string `protobuf:"bytes,1,rep,name=host,proto3" json:"host,omitempty"`
|
||||||
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
|
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
|
||||||
|
IdleTimeout int32 `protobuf:"varint,3,opt,name=idle_timeout,json=idleTimeout,proto3" json:"idle_timeout,omitempty"`
|
||||||
|
HealthCheckTimeout int32 `protobuf:"varint,4,opt,name=health_check_timeout,json=healthCheckTimeout,proto3" json:"health_check_timeout,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
|
@ -80,6 +77,20 @@ func (x *Config) GetPath() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetIdleTimeout() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.IdleTimeout
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetHealthCheckTimeout() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.HealthCheckTimeout
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
var File_transport_internet_http_config_proto protoreflect.FileDescriptor
|
var File_transport_internet_http_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_transport_internet_http_config_proto_rawDesc = []byte{
|
var file_transport_internet_http_config_proto_rawDesc = []byte{
|
||||||
|
@ -87,18 +98,23 @@ var file_transport_internet_http_config_proto_rawDesc = []byte{
|
||||||
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
|
||||||
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
||||||
0x68, 0x74, 0x74, 0x70, 0x22, 0x30, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12,
|
0x68, 0x74, 0x74, 0x70, 0x22, 0x85, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
||||||
0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f,
|
0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x68,
|
||||||
0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||||
0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x42, 0x76, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
|
0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x64, 0x6c, 0x65, 0x5f,
|
||||||
0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,
|
0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x69,
|
||||||
0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69,
|
0x64, 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x68, 0x65,
|
||||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72,
|
0x61, 0x6c, 0x74, 0x68, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f,
|
||||||
0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68,
|
||||||
0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x74, 0x74, 0x70, 0xaa,
|
0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x76, 0x0a, 0x20,
|
||||||
0x02, 0x1c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,
|
0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
|
||||||
0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x62, 0x06,
|
0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x74, 0x74, 0x70,
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
|
||||||
|
0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72,
|
||||||
|
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
|
||||||
|
0x2f, 0x68, 0x74, 0x74, 0x70, 0xaa, 0x02, 0x1c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61,
|
||||||
|
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
||||||
|
0x48, 0x74, 0x74, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -9,4 +9,6 @@ option java_multiple_files = true;
|
||||||
message Config {
|
message Config {
|
||||||
repeated string host = 1;
|
repeated string host = 1;
|
||||||
string path = 2;
|
string path = 2;
|
||||||
|
int32 idle_timeout = 3;
|
||||||
|
int32 health_check_timeout = 4;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
|
@ -20,8 +21,7 @@ import (
|
||||||
|
|
||||||
type dialerConf struct {
|
type dialerConf struct {
|
||||||
net.Destination
|
net.Destination
|
||||||
*internet.SocketConfig
|
*internet.MemoryStreamConfig
|
||||||
*tls.Config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -29,7 +29,7 @@ var (
|
||||||
globalDialerAccess sync.Mutex
|
globalDialerAccess sync.Mutex
|
||||||
)
|
)
|
||||||
|
|
||||||
func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.Config, sockopt *internet.SocketConfig) (*http.Client, error) {
|
func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (*http.Client, error) {
|
||||||
globalDialerAccess.Lock()
|
globalDialerAccess.Lock()
|
||||||
defer globalDialerAccess.Unlock()
|
defer globalDialerAccess.Unlock()
|
||||||
|
|
||||||
|
@ -37,7 +37,14 @@ func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.C
|
||||||
globalDialerMap = make(map[dialerConf]*http.Client)
|
globalDialerMap = make(map[dialerConf]*http.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
if client, found := globalDialerMap[dialerConf{dest, sockopt, tlsSettings}]; found {
|
httpSettings := streamSettings.ProtocolSettings.(*Config)
|
||||||
|
tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
|
||||||
|
if tlsConfig == nil {
|
||||||
|
return nil, newError("TLS must be enabled for http transport.").AtWarning()
|
||||||
|
}
|
||||||
|
sockopt := streamSettings.SocketSettings
|
||||||
|
|
||||||
|
if client, found := globalDialerMap[dialerConf{dest, streamSettings}]; found {
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,25 +93,26 @@ func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.C
|
||||||
}
|
}
|
||||||
return cn, nil
|
return cn, nil
|
||||||
},
|
},
|
||||||
TLSClientConfig: tlsSettings.GetTLSConfig(tls.WithDestination(dest)),
|
TLSClientConfig: tlsConfig.GetTLSConfig(tls.WithDestination(dest)),
|
||||||
|
}
|
||||||
|
|
||||||
|
if httpSettings.IdleTimeout > 0 || httpSettings.HealthCheckTimeout > 0 {
|
||||||
|
transport.ReadIdleTimeout = time.Second * time.Duration(httpSettings.IdleTimeout)
|
||||||
|
transport.PingTimeout = time.Second * time.Duration(httpSettings.HealthCheckTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
}
|
}
|
||||||
|
|
||||||
globalDialerMap[dialerConf{dest, sockopt, tlsSettings}] = client
|
globalDialerMap[dialerConf{dest, streamSettings}] = client
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dial dials a new TCP connection to the given destination.
|
// Dial dials a new TCP connection to the given destination.
|
||||||
func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {
|
func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {
|
||||||
httpSettings := streamSettings.ProtocolSettings.(*Config)
|
httpSettings := streamSettings.ProtocolSettings.(*Config)
|
||||||
tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
|
client, err := getHTTPClient(ctx, dest, streamSettings)
|
||||||
if tlsConfig == nil {
|
|
||||||
return nil, newError("TLS must be enabled for http transport.").AtWarning()
|
|
||||||
}
|
|
||||||
client, err := getHTTPClient(ctx, dest, tlsConfig, streamSettings.SocketSettings)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue