Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 38 additions & 18 deletions client/internal/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ import (
"strings"
)

const (
dnsScheme = "dns"
unixScheme = "unix"
unixAbstractScheme = "unix-abstract"
vsockScheme = "vsock"
httpScheme = "http"
httpsScheme = "https"
)

// Parsed represents a parsed gRPC endpoint.
type Parsed struct {
Target string
Expand All @@ -37,6 +46,7 @@ func ParseGRPCEndpoint(endpoint string) (Parsed, error) {
var hostname string
var tls bool

noSchemeInEndpoint := false
urlSplit := strings.Split(target, ":")
if len(urlSplit) == 3 && !strings.Contains(target, "://") {
target = strings.Replace(target, ":", "://", 1)
Expand All @@ -46,13 +56,14 @@ func ParseGRPCEndpoint(endpoint string) (Parsed, error) {
urlSplit = strings.Split(target, "://")
if len(urlSplit) == 1 {
target = "dns://" + target
noSchemeInEndpoint = true
} else {
scheme := urlSplit[0]
if !schemeKnown(scheme) {
return Parsed{}, fmt.Errorf(("unknown scheme: %q"), scheme)
}

if scheme == "dns" {
if scheme == dnsScheme {
urlSplit = strings.Split(target, "/")
if len(urlSplit) < 4 {
return Parsed{}, fmt.Errorf("invalid dns scheme: %q", target)
Expand All @@ -79,7 +90,7 @@ func ParseGRPCEndpoint(endpoint string) (Parsed, error) {
}

if ptarget.Query().Has("tls") {
if ptarget.Scheme == "http" || ptarget.Scheme == "https" {
if ptarget.Scheme == httpScheme || ptarget.Scheme == httpsScheme {
return Parsed{}, errors.New("cannot use tls query parameter with http(s) scheme")
}

Expand All @@ -92,11 +103,11 @@ func ParseGRPCEndpoint(endpoint string) (Parsed, error) {
}

scheme := ptarget.Scheme
if scheme == "https" {
if scheme == httpsScheme {
tls = true
}
if scheme == "http" || scheme == "https" {
scheme = "dns"
if scheme == httpScheme || scheme == httpsScheme {
scheme = dnsScheme
}

hostname = ptarget.Host
Expand All @@ -112,28 +123,28 @@ func ParseGRPCEndpoint(endpoint string) (Parsed, error) {
}

if len(hostname) == 0 {
if scheme == "dns" {
if scheme == dnsScheme {
hostname = "localhost"
} else {
hostname = ptarget.Path
}
}

switch scheme {
case "unix":
case unixScheme:
separator := ":"
if strings.HasPrefix(endpoint, "unix://") {
separator = "://"
}
target = scheme + separator + hostname

case "vsock":
case vsockScheme:
target = scheme + ":" + hostname + ":" + port

case "unix-abstract":
case unixAbstractScheme:
target = scheme + ":" + hostname

case "dns":
case dnsScheme:
if len(ptarget.Path) > 0 {
return Parsed{}, fmt.Errorf("path is not allowed: %q", ptarget.Path)
}
Expand All @@ -142,9 +153,18 @@ func ParseGRPCEndpoint(endpoint string) (Parsed, error) {
hostname = "[" + hostname + "]"
}
if len(dnsAuthority) > 0 {
dnsAuthority = "//" + dnsAuthority + "/"
target = scheme + "://" + dnsAuthority + "/" + hostname + ":" + port
} else if ptarget.Scheme == dnsScheme && !noSchemeInEndpoint {
// when real scheme is dns, keep the previous format (dns:hostname:port)
target = scheme + ":" + hostname + ":" + port
} else {
// Use passthrough resolver (just host:port) instead of the dns: scheme.
// In gRPC v1.78, targets of the form dns:host:port can be treated as
// opaque by grpc.DialContext(), so the DNS resolver is not invoked.
// Using a bare host:port target makes grpc.DialContext() fall back to
// the passthrough resolver, which resolves and connects correctly.
target = hostname + ":" + port
}
target = scheme + ":" + dnsAuthority + hostname + ":" + port

default:
return Parsed{}, fmt.Errorf("unsupported scheme: %q", scheme)
Expand All @@ -158,12 +178,12 @@ func ParseGRPCEndpoint(endpoint string) (Parsed, error) {

func schemeKnown(scheme string) bool {
for _, s := range []string{
"dns",
"unix",
"unix-abstract",
"vsock",
"http",
"https",
dnsScheme,
unixScheme,
unixAbstractScheme,
vsockScheme,
httpScheme,
httpsScheme,
} {
if scheme == s {
return true
Expand Down
30 changes: 15 additions & 15 deletions client/internal/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,52 +31,52 @@ func TestParse(t *testing.T) {
expError: true,
},
":5000": {
expTarget: "dns:localhost:5000",
expTarget: "localhost:5000",
expTLS: false,
expError: false,
},
":5000?tls=false": {
expTarget: "dns:localhost:5000",
expTarget: "localhost:5000",
expTLS: false,
expError: false,
},
":5000?tls=true": {
expTarget: "dns:localhost:5000",
expTarget: "localhost:5000",
expTLS: true,
expError: false,
},
"myhost": {
expTarget: "dns:myhost:443",
expTarget: "myhost:443",
expTLS: false,
expError: false,
},
"myhost?tls=false": {
expTarget: "dns:myhost:443",
expTarget: "myhost:443",
expTLS: false,
expError: false,
},
"myhost?tls=true": {
expTarget: "dns:myhost:443",
expTarget: "myhost:443",
expTLS: true,
expError: false,
},
"myhost:443": {
expTarget: "dns:myhost:443",
expTarget: "myhost:443",
expTLS: false,
expError: false,
},
"myhost:443?tls=false": {
expTarget: "dns:myhost:443",
expTarget: "myhost:443",
expTLS: false,
expError: false,
},
"myhost:443?tls=true": {
expTarget: "dns:myhost:443",
expTarget: "myhost:443",
expTLS: true,
expError: false,
},
"http://myhost": {
expTarget: "dns:myhost:443",
expTarget: "myhost:443",
expTLS: false,
expError: false,
},
Expand All @@ -91,7 +91,7 @@ func TestParse(t *testing.T) {
expError: true,
},
"http://myhost:443": {
expTarget: "dns:myhost:443",
expTarget: "myhost:443",
expTLS: false,
expError: false,
},
Expand All @@ -106,7 +106,7 @@ func TestParse(t *testing.T) {
expError: true,
},
"http://myhost:5000": {
expTarget: "dns:myhost:5000",
expTarget: "myhost:5000",
expTLS: false,
expError: false,
},
Expand All @@ -121,7 +121,7 @@ func TestParse(t *testing.T) {
expError: true,
},
"https://myhost:443": {
expTarget: "dns:myhost:443",
expTarget: "myhost:443",
expTLS: true,
expError: false,
},
Expand Down Expand Up @@ -251,12 +251,12 @@ func TestParse(t *testing.T) {
expError: false,
},
"https://[2001:db8:1f70::999:de8:7648:6e8]": {
expTarget: "dns:[2001:db8:1f70::999:de8:7648:6e8]:443",
expTarget: "[2001:db8:1f70::999:de8:7648:6e8]:443",
expTLS: true,
expError: false,
},
"https://[2001:db8:1f70::999:de8:7648:6e8]:5000": {
expTarget: "dns:[2001:db8:1f70::999:de8:7648:6e8]:5000",
expTarget: "[2001:db8:1f70::999:de8:7648:6e8]:5000",
expTLS: true,
expError: false,
},
Expand Down
Loading