Add DialOption to overwrite :authority pseudo-header

The :authority pseudo-header for a gRPC Client defaults to the host
portion of the dialed target and can only be overwritten by providing a
TransportCredentials. However, there are cases where setting this header
independent of any tranport security is valid. In my particular case,
in order to leverage Envoy for request routing, the cluster/service name
must be provided in the :authority header. This may also be useful in a
testing context.

This patch adds a DialOption to overwrite the authority header,
even if TransportCredentials are provided (I'd imagine you'd only ever
need to specify one or the other).
This commit is contained in:
Chris Roche 2017-02-03 17:01:38 -08:00
parent 21f8ed3094
commit 84bee50bda
3 changed files with 30 additions and 1 deletions

View File

@ -263,6 +263,15 @@ func WithStreamInterceptor(f StreamClientInterceptor) DialOption {
}
}
// WithAuthority returns a DialOption that specifies the value to be used as
// the :authority pseudo-header. This value overrides the :authority value
// provided by TransportCredentials if present.
func WithAuthority(a string) DialOption {
return func(o *dialOptions) {
o.copts.Authority = a
}
}
// Dial creates a client connection to the given target.
func Dial(target string, opts ...DialOption) (*ClientConn, error) {
return DialContext(context.Background(), target, opts...)
@ -319,7 +328,9 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *
cc.dopts.bs = DefaultBackoffConfig
}
creds := cc.dopts.copts.TransportCredentials
if creds != nil && creds.Info().ServerName != "" {
if cc.dopts.copts.Authority != "" {
cc.authority = cc.dopts.copts.Authority
} else if creds != nil && creds.Info().ServerName != "" {
cc.authority = creds.Info().ServerName
} else {
colonPos := strings.LastIndex(target, ":")

View File

@ -85,6 +85,22 @@ func TestTLSServerNameOverwrite(t *testing.T) {
}
}
func TestWithAuthority(t *testing.T) {
overwriteServerName := "over.write.server.name"
creds, err := credentials.NewClientTLSFromFile(tlsDir+"ca.pem", "transport.security.overwrite")
if err != nil {
t.Fatalf("Failed to create credentials %v", err)
}
conn, err := Dial("Non-Existent.Server:80", WithTransportCredentials(creds), WithAuthority(overwriteServerName))
if err != nil {
t.Fatalf("Dial(_, _) = _, %v, want _, <nil>", err)
}
conn.Close()
if conn.authority != overwriteServerName {
t.Fatalf("%v.authority = %v, want %v", conn, conn.authority, overwriteServerName)
}
}
func TestDialContextCancel(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
cancel()

View File

@ -374,6 +374,8 @@ func NewServerTransport(protocol string, conn net.Conn, config *ServerConfig) (S
type ConnectOptions struct {
// UserAgent is the application user agent.
UserAgent string
// Authority is the :authority pseudo-header to use.
Authority string
// Dialer specifies how to dial a network address.
Dialer func(context.Context, string) (net.Conn, error)
// FailOnNonTempDialError specifies if gRPC fails on non-temporary dial errors.