mirror of https://github.com/grpc/grpc-go.git
support unix-abstract schema (#4079)
This commit is contained in:
parent
666aea1fb3
commit
39a500abb9
|
@ -270,7 +270,7 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *
|
||||||
cc.authority = creds.Info().ServerName
|
cc.authority = creds.Info().ServerName
|
||||||
} else if cc.dopts.insecure && cc.dopts.authority != "" {
|
} else if cc.dopts.insecure && cc.dopts.authority != "" {
|
||||||
cc.authority = cc.dopts.authority
|
cc.authority = cc.dopts.authority
|
||||||
} else if strings.HasPrefix(cc.target, "unix:") {
|
} else if strings.HasPrefix(cc.target, "unix:") || strings.HasPrefix(cc.target, "unix-abstract:") {
|
||||||
cc.authority = "localhost"
|
cc.authority = "localhost"
|
||||||
} else if strings.HasPrefix(cc.parsedTarget.Endpoint, ":") {
|
} else if strings.HasPrefix(cc.parsedTarget.Endpoint, ":") {
|
||||||
cc.authority = "localhost" + cc.parsedTarget.Endpoint
|
cc.authority = "localhost" + cc.parsedTarget.Endpoint
|
||||||
|
|
|
@ -41,10 +41,30 @@ func split2(s, sep string) (string, string, bool) {
|
||||||
// not parse "unix:[path]" cases. This should be true in cases where a custom
|
// not parse "unix:[path]" cases. This should be true in cases where a custom
|
||||||
// dialer is present, to prevent a behavior change.
|
// dialer is present, to prevent a behavior change.
|
||||||
//
|
//
|
||||||
// If target is not a valid scheme://authority/endpoint, it returns {Endpoint:
|
// If target is not a valid scheme://authority/endpoint as specified in
|
||||||
// target}.
|
// https://github.com/grpc/grpc/blob/master/doc/naming.md,
|
||||||
|
// it returns {Endpoint: target}.
|
||||||
func ParseTarget(target string, skipUnixColonParsing bool) (ret resolver.Target) {
|
func ParseTarget(target string, skipUnixColonParsing bool) (ret resolver.Target) {
|
||||||
var ok bool
|
var ok bool
|
||||||
|
if strings.HasPrefix(target, "unix-abstract:") {
|
||||||
|
if strings.HasPrefix(target, "unix-abstract://") {
|
||||||
|
// Maybe, with Authority specified, try to parse it
|
||||||
|
var remain string
|
||||||
|
ret.Scheme, remain, _ = split2(target, "://")
|
||||||
|
ret.Authority, ret.Endpoint, ok = split2(remain, "/")
|
||||||
|
if !ok {
|
||||||
|
// No Authority, add the "//" back
|
||||||
|
ret.Endpoint = "//" + remain
|
||||||
|
} else {
|
||||||
|
// Found Authority, add the "/" back
|
||||||
|
ret.Endpoint = "/" + ret.Endpoint
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Without Authority specified, split target on ":"
|
||||||
|
ret.Scheme, ret.Endpoint, _ = split2(target, ":")
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
ret.Scheme, ret.Endpoint, ok = split2(target, "://")
|
ret.Scheme, ret.Endpoint, ok = split2(target, "://")
|
||||||
if !ok {
|
if !ok {
|
||||||
if strings.HasPrefix(target, "unix:") && !skipUnixColonParsing {
|
if strings.HasPrefix(target, "unix:") && !skipUnixColonParsing {
|
||||||
|
|
|
@ -84,6 +84,18 @@ func TestParseTargetString(t *testing.T) {
|
||||||
{targetStr: "unix:/a/b/c", want: resolver.Target{Scheme: "unix", Authority: "", Endpoint: "/a/b/c"}, wantWithDialer: resolver.Target{Scheme: "", Authority: "", Endpoint: "unix:/a/b/c"}},
|
{targetStr: "unix:/a/b/c", want: resolver.Target{Scheme: "unix", Authority: "", Endpoint: "/a/b/c"}, wantWithDialer: resolver.Target{Scheme: "", Authority: "", Endpoint: "unix:/a/b/c"}},
|
||||||
{targetStr: "unix:///a/b/c", want: resolver.Target{Scheme: "unix", Authority: "", Endpoint: "/a/b/c"}},
|
{targetStr: "unix:///a/b/c", want: resolver.Target{Scheme: "unix", Authority: "", Endpoint: "/a/b/c"}},
|
||||||
|
|
||||||
|
{targetStr: "unix-abstract:a/b/c", want: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "a/b/c"}},
|
||||||
|
{targetStr: "unix-abstract:a b", want: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "a b"}},
|
||||||
|
{targetStr: "unix-abstract:a:b", want: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "a:b"}},
|
||||||
|
{targetStr: "unix-abstract:a-b", want: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "a-b"}},
|
||||||
|
{targetStr: "unix-abstract:/ a///://::!@#$%^&*()b", want: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "/ a///://::!@#$%^&*()b"}},
|
||||||
|
{targetStr: "unix-abstract:passthrough:abc", want: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "passthrough:abc"}},
|
||||||
|
{targetStr: "unix-abstract:unix:///abc", want: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "unix:///abc"}},
|
||||||
|
{targetStr: "unix-abstract:///a/b/c", want: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "/a/b/c"}},
|
||||||
|
{targetStr: "unix-abstract://authority/a/b/c", want: resolver.Target{Scheme: "unix-abstract", Authority: "authority", Endpoint: "/a/b/c"}},
|
||||||
|
{targetStr: "unix-abstract:///", want: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "/"}},
|
||||||
|
{targetStr: "unix-abstract://authority", want: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "//authority"}},
|
||||||
|
|
||||||
{targetStr: "passthrough:///unix:///a/b/c", want: resolver.Target{Scheme: "passthrough", Authority: "", Endpoint: "unix:///a/b/c"}},
|
{targetStr: "passthrough:///unix:///a/b/c", want: resolver.Target{Scheme: "passthrough", Authority: "", Endpoint: "unix:///a/b/c"}},
|
||||||
} {
|
} {
|
||||||
got := ParseTarget(test.targetStr, false)
|
got := ParseTarget(test.targetStr, false)
|
||||||
|
|
|
@ -26,20 +26,28 @@ import (
|
||||||
"google.golang.org/grpc/resolver"
|
"google.golang.org/grpc/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
const scheme = "unix"
|
const unixScheme = "unix"
|
||||||
|
const unixAbstractScheme = "unix-abstract"
|
||||||
|
|
||||||
type builder struct{}
|
type builder struct {
|
||||||
|
scheme string
|
||||||
|
}
|
||||||
|
|
||||||
func (*builder) Build(target resolver.Target, cc resolver.ClientConn, _ resolver.BuildOptions) (resolver.Resolver, error) {
|
func (b *builder) Build(target resolver.Target, cc resolver.ClientConn, _ resolver.BuildOptions) (resolver.Resolver, error) {
|
||||||
if target.Authority != "" {
|
if target.Authority != "" {
|
||||||
return nil, fmt.Errorf("invalid (non-empty) authority: %v", target.Authority)
|
return nil, fmt.Errorf("invalid (non-empty) authority: %v", target.Authority)
|
||||||
}
|
}
|
||||||
cc.UpdateState(resolver.State{Addresses: []resolver.Address{networktype.Set(resolver.Address{Addr: target.Endpoint}, "unix")}})
|
addr := resolver.Address{Addr: target.Endpoint}
|
||||||
|
if b.scheme == unixAbstractScheme {
|
||||||
|
// prepend "\x00" to address for unix-abstract
|
||||||
|
addr.Addr = "\x00" + addr.Addr
|
||||||
|
}
|
||||||
|
cc.UpdateState(resolver.State{Addresses: []resolver.Address{networktype.Set(addr, "unix")}})
|
||||||
return &nopResolver{}, nil
|
return &nopResolver{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*builder) Scheme() string {
|
func (b *builder) Scheme() string {
|
||||||
return scheme
|
return b.scheme
|
||||||
}
|
}
|
||||||
|
|
||||||
type nopResolver struct {
|
type nopResolver struct {
|
||||||
|
@ -50,5 +58,6 @@ func (*nopResolver) ResolveNow(resolver.ResolveNowOptions) {}
|
||||||
func (*nopResolver) Close() {}
|
func (*nopResolver) Close() {}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
resolver.Register(&builder{})
|
resolver.Register(&builder{scheme: unixScheme})
|
||||||
|
resolver.Register(&builder{scheme: unixAbstractScheme})
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,7 +143,7 @@ func dial(ctx context.Context, fn func(context.Context, string) (net.Conn, error
|
||||||
address := addr.Addr
|
address := addr.Addr
|
||||||
networkType, ok := networktype.Get(addr)
|
networkType, ok := networktype.Get(addr)
|
||||||
if fn != nil {
|
if fn != nil {
|
||||||
if networkType == "unix" {
|
if networkType == "unix" && !strings.HasPrefix(address, "\x00") {
|
||||||
// For backward compatibility, if the user dialed "unix:///path",
|
// For backward compatibility, if the user dialed "unix:///path",
|
||||||
// the passthrough resolver would be used and the user's custom
|
// the passthrough resolver would be used and the user's custom
|
||||||
// dialer would see "unix:///path". Since the unix resolver is used
|
// dialer would see "unix:///path". Since the unix resolver is used
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -54,8 +55,10 @@ func authorityChecker(ctx context.Context, expectedAuthority string) (*testpb.Em
|
||||||
}
|
}
|
||||||
|
|
||||||
func runUnixTest(t *testing.T, address, target, expectedAuthority string, dialer func(context.Context, string) (net.Conn, error)) {
|
func runUnixTest(t *testing.T, address, target, expectedAuthority string, dialer func(context.Context, string) (net.Conn, error)) {
|
||||||
if err := os.RemoveAll(address); err != nil {
|
if !strings.HasPrefix(target, "unix-abstract:") {
|
||||||
t.Fatalf("Error removing socket file %v: %v\n", address, err)
|
if err := os.RemoveAll(address); err != nil {
|
||||||
|
t.Fatalf("Error removing socket file %v: %v\n", address, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ss := &stubserver.StubServer{
|
ss := &stubserver.StubServer{
|
||||||
EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
|
EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
|
||||||
|
@ -115,6 +118,13 @@ var authorityTests = []authorityTest{
|
||||||
authority: "unix:///tmp/sock.sock",
|
authority: "unix:///tmp/sock.sock",
|
||||||
dialTargetWant: "unix:///tmp/sock.sock",
|
dialTargetWant: "unix:///tmp/sock.sock",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "UnixAbstract",
|
||||||
|
address: "\x00abc efg",
|
||||||
|
target: "unix-abstract:abc efg",
|
||||||
|
authority: "localhost",
|
||||||
|
dialTargetWant: "\x00abc efg",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestUnix does end to end tests with the various supported unix target
|
// TestUnix does end to end tests with the various supported unix target
|
||||||
|
@ -140,7 +150,9 @@ func (s) TestUnixCustomDialer(t *testing.T) {
|
||||||
if address != test.dialTargetWant {
|
if address != test.dialTargetWant {
|
||||||
return nil, fmt.Errorf("expected target %v in custom dialer, instead got %v", test.dialTargetWant, address)
|
return nil, fmt.Errorf("expected target %v in custom dialer, instead got %v", test.dialTargetWant, address)
|
||||||
}
|
}
|
||||||
address = address[len("unix:"):]
|
if !strings.HasPrefix(test.target, "unix-abstract:") {
|
||||||
|
address = address[len("unix:"):]
|
||||||
|
}
|
||||||
return (&net.Dialer{}).DialContext(ctx, "unix", address)
|
return (&net.Dialer{}).DialContext(ctx, "unix", address)
|
||||||
}
|
}
|
||||||
runUnixTest(t, test.address, test.target, test.authority, dialer)
|
runUnixTest(t, test.address, test.target, test.authority, dialer)
|
||||||
|
|
Loading…
Reference in New Issue