Add custom path to gRPC (#1815)

pull/1885/head
Hirbod Behnam 2 years ago committed by yuhan6665
parent 6872be5cc3
commit 526c6789ed

@ -2,6 +2,7 @@ package grpc
import ( import (
"net/url" "net/url"
"strings"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
@ -15,6 +16,41 @@ func init() {
})) }))
} }
func (c *Config) getNormalizedName() string { func (c *Config) getServiceName() string {
return url.PathEscape(c.ServiceName) // Normal old school config
if !strings.HasPrefix(c.ServiceName, "/") {
return url.PathEscape(c.ServiceName)
}
// Otherwise new custom paths
rawServiceName := c.ServiceName[1:strings.LastIndex(c.ServiceName, "/")] // trim from first to last '/'
serviceNameParts := strings.Split(rawServiceName, "/")
for i := range serviceNameParts {
serviceNameParts[i] = url.PathEscape(serviceNameParts[i])
}
return strings.Join(serviceNameParts, "/")
}
func (c *Config) getTunStreamName() string {
// Normal old school config
if !strings.HasPrefix(c.ServiceName, "/") {
return "Tun"
}
// Otherwise new custom paths
endingPath := c.ServiceName[strings.LastIndex(c.ServiceName, "/")+1:] // from the last '/' to end of string
return url.PathEscape(strings.Split(endingPath, "|")[0])
}
func (c *Config) getTunMultiStreamName() string {
// Normal old school config
if !strings.HasPrefix(c.ServiceName, "/") {
return "TunMulti"
}
// Otherwise new custom paths
endingPath := c.ServiceName[strings.LastIndex(c.ServiceName, "/")+1:] // from the last '/' to end of string
streamNames := strings.Split(endingPath, "|")
if len(streamNames) == 1 { // client side. Service name is the full path to multi tun
return url.PathEscape(streamNames[0])
} else { // server side. The second part is the path to multi tun
return url.PathEscape(streamNames[1])
}
} }

@ -0,0 +1,111 @@
package grpc
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestConfig_GetServiceName(t *testing.T) {
tests := []struct {
TestName string
ServiceName string
Expected string
}{
{
TestName: "simple no absolute path",
ServiceName: "hello",
Expected: "hello",
},
{
TestName: "escape no absolute path",
ServiceName: "hello/world!",
Expected: "hello%2Fworld%21",
},
{
TestName: "absolute path",
ServiceName: "/my/sample/path/a|b",
Expected: "my/sample/path",
},
{
TestName: "escape absolute path",
ServiceName: "/hello /world!/a|b",
Expected: "hello%20/world%21",
},
}
for _, test := range tests {
t.Run(test.TestName, func(t *testing.T) {
config := Config{ServiceName: test.ServiceName}
assert.Equal(t, test.Expected, config.getServiceName())
})
}
}
func TestConfig_GetTunStreamName(t *testing.T) {
tests := []struct {
TestName string
ServiceName string
Expected string
}{
{
TestName: "no absolute path",
ServiceName: "hello",
Expected: "Tun",
},
{
TestName: "absolute path server",
ServiceName: "/my/sample/path/tun_service|multi_service",
Expected: "tun_service",
},
{
TestName: "absolute path client",
ServiceName: "/my/sample/path/tun_service",
Expected: "tun_service",
},
{
TestName: "escape absolute path client",
ServiceName: "/m y/sa !mple/pa\\th/tun\\_serv!ice",
Expected: "tun%5C_serv%21ice",
},
}
for _, test := range tests {
t.Run(test.TestName, func(t *testing.T) {
config := Config{ServiceName: test.ServiceName}
assert.Equal(t, test.Expected, config.getTunStreamName())
})
}
}
func TestConfig_GetTunMultiStreamName(t *testing.T) {
tests := []struct {
TestName string
ServiceName string
Expected string
}{
{
TestName: "no absolute path",
ServiceName: "hello",
Expected: "TunMulti",
},
{
TestName: "absolute path server",
ServiceName: "/my/sample/path/tun_service|multi_service",
Expected: "multi_service",
},
{
TestName: "absolute path client",
ServiceName: "/my/sample/path/multi_service",
Expected: "multi_service",
},
{
TestName: "escape absolute path client",
ServiceName: "/m y/sa !mple/pa\\th/mu%lti\\_serv!ice",
Expected: "mu%25lti%5C_serv%21ice",
},
}
for _, test := range tests {
t.Run(test.TestName, func(t *testing.T) {
config := Config{ServiceName: test.ServiceName}
assert.Equal(t, test.Expected, config.getTunMultiStreamName())
})
}
}

@ -54,15 +54,16 @@ func dialgRPC(ctx context.Context, dest net.Destination, streamSettings *interne
} }
client := encoding.NewGRPCServiceClient(conn) client := encoding.NewGRPCServiceClient(conn)
if grpcSettings.MultiMode { if grpcSettings.MultiMode {
newError("using gRPC multi mode").AtDebug().WriteToLog() newError("using gRPC multi mode service name: `" + grpcSettings.getServiceName() + "` stream name: `" + grpcSettings.getTunMultiStreamName() + "`").AtDebug().WriteToLog()
grpcService, err := client.(encoding.GRPCServiceClientX).TunMultiCustomName(ctx, grpcSettings.getNormalizedName()) grpcService, err := client.(encoding.GRPCServiceClientX).TunMultiCustomName(ctx, grpcSettings.getServiceName(), grpcSettings.getTunMultiStreamName())
if err != nil { if err != nil {
return nil, newError("Cannot dial gRPC").Base(err) return nil, newError("Cannot dial gRPC").Base(err)
} }
return encoding.NewMultiHunkConn(grpcService, nil), nil return encoding.NewMultiHunkConn(grpcService, nil), nil
} }
grpcService, err := client.(encoding.GRPCServiceClientX).TunCustomName(ctx, grpcSettings.getNormalizedName()) newError("using gRPC tun mode service name: `" + grpcSettings.getServiceName() + "` stream name: `" + grpcSettings.getTunStreamName() + "`").AtDebug().WriteToLog()
grpcService, err := client.(encoding.GRPCServiceClientX).TunCustomName(ctx, grpcSettings.getServiceName(), grpcSettings.getTunStreamName())
if err != nil { if err != nil {
return nil, newError("Cannot dial gRPC").Base(err) return nil, newError("Cannot dial gRPC").Base(err)
} }

@ -6,20 +6,20 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
) )
func ServerDesc(name string) grpc.ServiceDesc { func ServerDesc(name, tun, tunMulti string) grpc.ServiceDesc {
return grpc.ServiceDesc{ return grpc.ServiceDesc{
ServiceName: name, ServiceName: name,
HandlerType: (*GRPCServiceServer)(nil), HandlerType: (*GRPCServiceServer)(nil),
Methods: []grpc.MethodDesc{}, Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{ Streams: []grpc.StreamDesc{
{ {
StreamName: "Tun", StreamName: tun,
Handler: _GRPCService_Tun_Handler, Handler: _GRPCService_Tun_Handler,
ServerStreams: true, ServerStreams: true,
ClientStreams: true, ClientStreams: true,
}, },
{ {
StreamName: "TunMulti", StreamName: tunMulti,
Handler: _GRPCService_TunMulti_Handler, Handler: _GRPCService_TunMulti_Handler,
ServerStreams: true, ServerStreams: true,
ClientStreams: true, ClientStreams: true,
@ -29,8 +29,8 @@ func ServerDesc(name string) grpc.ServiceDesc {
} }
} }
func (c *gRPCServiceClient) TunCustomName(ctx context.Context, name string, opts ...grpc.CallOption) (GRPCService_TunClient, error) { func (c *gRPCServiceClient) TunCustomName(ctx context.Context, name, tun string, opts ...grpc.CallOption) (GRPCService_TunClient, error) {
stream, err := c.cc.NewStream(ctx, &ServerDesc(name).Streams[0], "/"+name+"/Tun", opts...) stream, err := c.cc.NewStream(ctx, &ServerDesc(name, tun, "").Streams[0], "/"+name+"/"+tun, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -38,8 +38,8 @@ func (c *gRPCServiceClient) TunCustomName(ctx context.Context, name string, opts
return x, nil return x, nil
} }
func (c *gRPCServiceClient) TunMultiCustomName(ctx context.Context, name string, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error) { func (c *gRPCServiceClient) TunMultiCustomName(ctx context.Context, name, tunMulti string, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error) {
stream, err := c.cc.NewStream(ctx, &ServerDesc(name).Streams[1], "/"+name+"/TunMulti", opts...) stream, err := c.cc.NewStream(ctx, &ServerDesc(name, "", tunMulti).Streams[1], "/"+name+"/"+tunMulti, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -48,13 +48,13 @@ func (c *gRPCServiceClient) TunMultiCustomName(ctx context.Context, name string,
} }
type GRPCServiceClientX interface { type GRPCServiceClientX interface {
TunCustomName(ctx context.Context, name string, opts ...grpc.CallOption) (GRPCService_TunClient, error) TunCustomName(ctx context.Context, name, tun string, opts ...grpc.CallOption) (GRPCService_TunClient, error)
TunMultiCustomName(ctx context.Context, name string, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error) TunMultiCustomName(ctx context.Context, name, tunMulti string, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error)
Tun(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunClient, error) Tun(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunClient, error)
TunMulti(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error) TunMulti(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error)
} }
func RegisterGRPCServiceServerX(s *grpc.Server, srv GRPCServiceServer, name string) { func RegisterGRPCServiceServerX(s *grpc.Server, srv GRPCServiceServer, name, tun, tunMulti string) {
desc := ServerDesc(name) desc := ServerDesc(name, tun, tunMulti)
s.RegisterService(&desc, srv) s.RegisterService(&desc, srv)
} }

@ -125,7 +125,8 @@ func Listen(ctx context.Context, address net.Address, port net.Port, settings *i
} }
} }
encoding.RegisterGRPCServiceServerX(s, listener, grpcSettings.getNormalizedName()) newError("gRPC listen for service name `" + grpcSettings.getServiceName() + "` tun `" + grpcSettings.getTunStreamName() + "` multi tun `" + grpcSettings.getTunMultiStreamName() + "`").AtDebug().WriteToLog()
encoding.RegisterGRPCServiceServerX(s, listener, grpcSettings.getServiceName(), grpcSettings.getTunStreamName(), grpcSettings.getTunMultiStreamName())
if config := reality.ConfigFromStreamSettings(settings); config != nil { if config := reality.ConfigFromStreamSettings(settings); config != nil {
streamListener = goreality.NewListener(streamListener, config.GetREALITYConfig()) streamListener = goreality.NewListener(streamListener, config.GetREALITYConfig())

Loading…
Cancel
Save