Skip to content

Commit

Permalink
support unix-abstract schema (#4079)
Browse files Browse the repository at this point in the history
  • Loading branch information
Edmond committed Dec 22, 2020
1 parent 666aea1 commit 39a500a
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 14 deletions.
2 changes: 1 addition & 1 deletion clientconn.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 22 additions & 2 deletions internal/grpcutil/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
12 changes: 12 additions & 0 deletions internal/grpcutil/target_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
23 changes: 16 additions & 7 deletions internal/resolver/unix/unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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})
}
2 changes: 1 addition & 1 deletion internal/transport/http2_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 15 additions & 3 deletions test/authority_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"fmt"
"net"
"os"
"strings"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down

0 comments on commit 39a500a

Please sign in to comment.