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
|
||||
} else if cc.dopts.insecure && 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"
|
||||
} else if strings.HasPrefix(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
|
||||
// dialer is present, to prevent a behavior change.
|
||||
//
|
||||
// If target is not a valid scheme://authority/endpoint, it returns {Endpoint:
|
||||
// target}.
|
||||
// If target is not a valid scheme://authority/endpoint as specified in
|
||||
// https://github.com/grpc/grpc/blob/master/doc/naming.md,
|
||||
// it returns {Endpoint: target}.
|
||||
func ParseTarget(target string, skipUnixColonParsing bool) (ret resolver.Target) {
|
||||
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, "://")
|
||||
if !ok {
|
||||
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"}},
|
||||
|
||||
{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"}},
|
||||
} {
|
||||
got := ParseTarget(test.targetStr, false)
|
||||
|
|
|
@ -26,20 +26,28 @@ import (
|
|||
"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 != "" {
|
||||
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
|
||||
}
|
||||
|
||||
func (*builder) Scheme() string {
|
||||
return scheme
|
||||
func (b *builder) Scheme() string {
|
||||
return b.scheme
|
||||
}
|
||||
|
||||
type nopResolver struct {
|
||||
|
@ -50,5 +58,6 @@ func (*nopResolver) ResolveNow(resolver.ResolveNowOptions) {}
|
|||
func (*nopResolver) Close() {}
|
||||
|
||||
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
|
||||
networkType, ok := networktype.Get(addr)
|
||||
if fn != nil {
|
||||
if networkType == "unix" {
|
||||
if networkType == "unix" && !strings.HasPrefix(address, "\x00") {
|
||||
// For backward compatibility, if the user dialed "unix:///path",
|
||||
// the passthrough resolver would be used and the user's custom
|
||||
// dialer would see "unix:///path". Since the unix resolver is used
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"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)) {
|
||||
if err := os.RemoveAll(address); err != nil {
|
||||
t.Fatalf("Error removing socket file %v: %v\n", address, err)
|
||||
if !strings.HasPrefix(target, "unix-abstract:") {
|
||||
if err := os.RemoveAll(address); err != nil {
|
||||
t.Fatalf("Error removing socket file %v: %v\n", address, err)
|
||||
}
|
||||
}
|
||||
ss := &stubserver.StubServer{
|
||||
EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
|
||||
|
@ -115,6 +118,13 @@ var authorityTests = []authorityTest{
|
|||
authority: "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
|
||||
|
@ -140,7 +150,9 @@ func (s) TestUnixCustomDialer(t *testing.T) {
|
|||
if address != test.dialTargetWant {
|
||||
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)
|
||||
}
|
||||
runUnixTest(t, test.address, test.target, test.authority, dialer)
|
||||
|
|
Loading…
Reference in New Issue