client: Use first endpoint as http2 authority header

This commit is contained in:
Marek Siarkowicz 2021-09-17 12:20:59 +02:00
parent ec419f8613
commit c929a917b6
3 changed files with 49 additions and 22 deletions

View File

@ -297,9 +297,7 @@ func (c *Client) dial(creds grpccredentials.TransportCredentials, dopts ...grpc.
dctx, cancel = context.WithTimeout(c.ctx, c.cfg.DialTimeout) dctx, cancel = context.WithTimeout(c.ctx, c.cfg.DialTimeout)
defer cancel() // TODO: Is this right for cases where grpc.WithBlock() is not set on the dial options? defer cancel() // TODO: Is this right for cases where grpc.WithBlock() is not set on the dial options?
} }
target := fmt.Sprintf("%s://%p/%s", resolver.Schema, c, authority(c.endpoints[0]))
initialEndpoints := strings.Join(c.Endpoints(), ";")
target := fmt.Sprintf("%s://%p/#initially=[%s]", resolver.Schema, c, initialEndpoints)
conn, err := grpc.DialContext(dctx, target, opts...) conn, err := grpc.DialContext(dctx, target, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
@ -307,6 +305,20 @@ func (c *Client) dial(creds grpccredentials.TransportCredentials, dopts ...grpc.
return conn, nil return conn, nil
} }
func authority(endpoint string) string {
spl := strings.SplitN(endpoint, "://", 2)
if len(spl) < 2 {
if strings.HasPrefix(endpoint, "unix:") {
return endpoint[len("unix:"):]
}
if strings.HasPrefix(endpoint, "unixs:") {
return endpoint[len("unixs:"):]
}
return endpoint
}
return spl[1]
}
func (c *Client) credentialsForEndpoint(ep string) grpccredentials.TransportCredentials { func (c *Client) credentialsForEndpoint(ep string) grpccredentials.TransportCredentials {
r := endpoint.RequiresCredentials(ep) r := endpoint.RequiresCredentials(ep)
switch r { switch r {

View File

@ -37,44 +37,44 @@ func TestAuthority(t *testing.T) {
clientURLPattern string clientURLPattern string
// Pattern used to validate authority received by server. Fields filled: // Pattern used to validate authority received by server. Fields filled:
// %s - list of endpoints concatenated with ";" // %d - will be filled with first member grpc port
expectAuthorityPattern string expectAuthorityPattern string
}{ }{
{ {
name: "http://domain[:port]", name: "http://domain[:port]",
clientURLPattern: "http://localhost:%d", clientURLPattern: "http://localhost:%d",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "localhost:%d",
}, },
{ {
name: "http://address[:port]", name: "http://address[:port]",
clientURLPattern: "http://127.0.0.1:%d", clientURLPattern: "http://127.0.0.1:%d",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "127.0.0.1:%d",
}, },
{ {
name: "https://domain[:port] insecure", name: "https://domain[:port] insecure",
useTLS: true, useTLS: true,
useInsecureTLS: true, useInsecureTLS: true,
clientURLPattern: "https://localhost:%d", clientURLPattern: "https://localhost:%d",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "localhost:%d",
}, },
{ {
name: "https://address[:port] insecure", name: "https://address[:port] insecure",
useTLS: true, useTLS: true,
useInsecureTLS: true, useInsecureTLS: true,
clientURLPattern: "https://127.0.0.1:%d", clientURLPattern: "https://127.0.0.1:%d",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "127.0.0.1:%d",
}, },
{ {
name: "https://domain[:port]", name: "https://domain[:port]",
useTLS: true, useTLS: true,
clientURLPattern: "https://localhost:%d", clientURLPattern: "https://localhost:%d",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "localhost:%d",
}, },
{ {
name: "https://address[:port]", name: "https://address[:port]",
useTLS: true, useTLS: true,
clientURLPattern: "https://127.0.0.1:%d", clientURLPattern: "https://127.0.0.1:%d",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "127.0.0.1:%d",
}, },
} }
for _, tc := range tcs { for _, tc := range tcs {
@ -105,7 +105,7 @@ func TestAuthority(t *testing.T) {
} }
executeWithTimeout(t, 5*time.Second, func() { executeWithTimeout(t, 5*time.Second, func() {
assertAuthority(t, fmt.Sprintf(tc.expectAuthorityPattern, strings.Join(endpoints, ";")), epc) assertAuthority(t, fmt.Sprintf(tc.expectAuthorityPattern, 20000), epc)
}) })
}) })

View File

@ -37,57 +37,58 @@ func TestAuthority(t *testing.T) {
clientURLPattern string clientURLPattern string
// Pattern used to validate authority received by server. Fields filled: // Pattern used to validate authority received by server. Fields filled:
// %s - list of endpoints concatenated with ";" // %d - will be filled with first member grpc port
// %s - will be filled with first member name
expectAuthorityPattern string expectAuthorityPattern string
}{ }{
{ {
name: "unix:path", name: "unix:path",
clientURLPattern: "unix:localhost:%s", clientURLPattern: "unix:localhost:%s",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "localhost:%s",
}, },
{ {
name: "unix://absolute_path", name: "unix://absolute_path",
clientURLPattern: "unix://localhost:%s", clientURLPattern: "unix://localhost:%s",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "localhost:%s",
}, },
// "unixs" is not standard schema supported by etcd // "unixs" is not standard schema supported by etcd
{ {
name: "unixs:absolute_path", name: "unixs:absolute_path",
useTLS: true, useTLS: true,
clientURLPattern: "unixs:localhost:%s", clientURLPattern: "unixs:localhost:%s",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "localhost:%s",
}, },
{ {
name: "unixs://absolute_path", name: "unixs://absolute_path",
useTLS: true, useTLS: true,
clientURLPattern: "unixs://localhost:%s", clientURLPattern: "unixs://localhost:%s",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "localhost:%s",
}, },
{ {
name: "http://domain[:port]", name: "http://domain[:port]",
useTCP: true, useTCP: true,
clientURLPattern: "http://localhost:%d", clientURLPattern: "http://localhost:%d",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "localhost:%d",
}, },
{ {
name: "https://domain[:port]", name: "https://domain[:port]",
useTLS: true, useTLS: true,
useTCP: true, useTCP: true,
clientURLPattern: "https://localhost:%d", clientURLPattern: "https://localhost:%d",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "localhost:%d",
}, },
{ {
name: "http://address[:port]", name: "http://address[:port]",
useTCP: true, useTCP: true,
clientURLPattern: "http://127.0.0.1:%d", clientURLPattern: "http://127.0.0.1:%d",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "127.0.0.1:%d",
}, },
{ {
name: "https://address[:port]", name: "https://address[:port]",
useTCP: true, useTCP: true,
useTLS: true, useTLS: true,
clientURLPattern: "https://127.0.0.1:%d", clientURLPattern: "https://127.0.0.1:%d",
expectAuthorityPattern: "#initially=[%s]", expectAuthorityPattern: "127.0.0.1:%d",
}, },
} }
for _, tc := range tcs { for _, tc := range tcs {
@ -102,7 +103,6 @@ func TestAuthority(t *testing.T) {
cfg, tlsConfig := setupTLS(t, tc.useTLS, cfg) cfg, tlsConfig := setupTLS(t, tc.useTLS, cfg)
clus := NewClusterV3(t, &cfg) clus := NewClusterV3(t, &cfg)
defer clus.Terminate(t) defer clus.Terminate(t)
endpoints := templateEndpoints(t, tc.clientURLPattern, clus)
kv := setupClient(t, tc.clientURLPattern, clus, tlsConfig) kv := setupClient(t, tc.clientURLPattern, clus, tlsConfig)
defer kv.Close() defer kv.Close()
@ -112,7 +112,7 @@ func TestAuthority(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
assertAuthority(t, fmt.Sprintf(tc.expectAuthorityPattern, strings.Join(endpoints, ";")), clus) assertAuthority(t, templateAuthority(t, tc.expectAuthorityPattern, clus.Members[0]), clus)
}) })
} }
} }
@ -165,6 +165,21 @@ func templateEndpoints(t *testing.T, pattern string, clus *ClusterV3) []string {
return endpoints return endpoints
} }
func templateAuthority(t *testing.T, pattern string, m *member) string {
t.Helper()
authority := pattern
if strings.Contains(authority, "%d") {
authority = fmt.Sprintf(authority, GrpcPortNumber(m.UniqNumber, m.MemberNumber))
}
if strings.Contains(authority, "%s") {
authority = fmt.Sprintf(authority, m.Name)
}
if strings.Contains(authority, "%") {
t.Fatalf("Failed to template pattern, %% symbol left %q", authority)
}
return authority
}
func assertAuthority(t *testing.T, expectedAuthority string, clus *ClusterV3) { func assertAuthority(t *testing.T, expectedAuthority string, clus *ClusterV3) {
t.Helper() t.Helper()
requestsFound := 0 requestsFound := 0