diff --git a/rpc/client/connect.go b/rpc/client/connect.go index 1e36623..8b7db4f 100644 --- a/rpc/client/connect.go +++ b/rpc/client/connect.go @@ -3,6 +3,9 @@ package client import ( "context" "errors" + "fmt" + "net" + "net/url" "github.com/nspcc-dev/neofs-api-go/v2/rpc/grpc" grpcstd "google.golang.org/grpc" @@ -52,3 +55,33 @@ func (c *Client) openGRPCConn() error { return err } + +// ParseURI parses s as address and returns a host and a flag +// indicating that TLS is enabled. If multi-address is provided +// the argument is returned unchanged. +func ParseURI(s string) (string, bool, error) { + uri, err := url.ParseRequestURI(s) + if err != nil { + return s, false, nil + } + + // check if passed string was parsed correctly + // URIs that do not start with a slash after the scheme are interpreted as: + // `scheme:opaque` => if `opaque` is not empty, then it is supposed that URI + // is in `host:port` format + if uri.Host == "" { + uri.Host = uri.Scheme + uri.Scheme = grpcScheme // assume GRPC by default + if uri.Opaque != "" { + uri.Host = net.JoinHostPort(uri.Host, uri.Opaque) + } + } + + switch uri.Scheme { + case grpcTLSScheme, grpcScheme: + default: + return "", false, fmt.Errorf("unsupported scheme: %s", uri.Scheme) + } + + return uri.Host, uri.Scheme == grpcTLSScheme, nil +} diff --git a/rpc/client/options.go b/rpc/client/options.go index 2c276dc..f04fc9e 100644 --- a/rpc/client/options.go +++ b/rpc/client/options.go @@ -2,7 +2,6 @@ package client import ( "crypto/tls" - "net/url" "time" "google.golang.org/grpc" @@ -58,35 +57,23 @@ func WithNetworkAddress(v string) Option { // // Ignored if WithGRPCConn is provided. func WithNetworkURIAddress(addr string, tlsCfg *tls.Config) []Option { - uri, err := url.ParseRequestURI(addr) + host, isTLS, err := ParseURI(addr) if err != nil { - return []Option{WithNetworkAddress(addr)} - } - - // check if passed string was parsed correctly - // URIs that do not start with a slash after the scheme are interpreted as: - // `scheme:opaque` => if `opaque` is not empty, then it is supposed that URI - // is in `host:port` format - if uri.Opaque != "" { - return []Option{WithNetworkAddress(addr)} - } - - switch uri.Scheme { - case grpcScheme: - tlsCfg = nil - case grpcTLSScheme: - if tlsCfg == nil { - tlsCfg = &tls.Config{} - } - default: - // not supported scheme return nil } - return []Option{ - WithNetworkAddress(uri.Host), - WithTLSCfg(tlsCfg), + opts := make([]Option, 2) + opts[0] = WithNetworkAddress(host) + if isTLS { + if tlsCfg == nil { + tlsCfg = &tls.Config{} + } + opts[1] = WithTLSCfg(tlsCfg) + } else { + opts[1] = WithTLSCfg(nil) } + + return opts } // WithDialTimeout returns option to specify