github.com/searKing/golang/go@v1.2.74/net/resolver/target.go (about)

     1  // Copyright 2021 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package resolver
     6  
     7  import (
     8  	"fmt"
     9  	"net/url"
    10  	"strings"
    11  )
    12  
    13  // Target represents a target for gRPC, as specified in:
    14  // https://github.com/grpc/grpc/blob/master/doc/naming.md.
    15  // It is parsed from the target string that gets passed into Dial or DialContext
    16  // by the user. And gRPC passes it to the resolver and the balancer.
    17  //
    18  // If the target follows the naming spec, and the parsed scheme is registered
    19  // with gRPC, we will parse the target string according to the spec. If the
    20  // target does not contain a scheme or if the parsed scheme is not registered
    21  // (i.e. no corresponding resolver available to resolve the endpoint), we will
    22  // apply the default scheme, and will attempt to reparse it.
    23  //
    24  // Examples:
    25  //
    26  //   - "dns://some_authority/foo.bar"
    27  //     Target{Scheme: "dns", Authority: "some_authority", Endpoint: "foo.bar"}
    28  //   - "foo.bar"
    29  //     Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "foo.bar"}
    30  //   - "unknown_scheme://authority/endpoint"
    31  //     Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "unknown_scheme://authority/endpoint"}
    32  //
    33  // If the target does not contain a scheme, we will apply the default scheme, and set the Target to
    34  // be the full target string. e.g. "foo.bar" will be parsed into
    35  // &Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "foo.bar"}.
    36  //
    37  // If the parsed scheme is not registered (i.e. no corresponding resolver available to resolve the
    38  // endpoint), we set the Scheme to be the default scheme, and set the Endpoint to be the full target
    39  // string. e.g. target string "unknown_scheme://authority/endpoint" will be parsed into
    40  // &Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "unknown_scheme://authority/endpoint"}.
    41  
    42  type Target struct {
    43  	// Deprecated: use URL.Scheme instead.
    44  	Scheme string
    45  	// Deprecated: use URL.Host instead.
    46  	Authority string
    47  	// Deprecated: use URL.Path or URL.Opaque instead. The latter is set when
    48  	// the former is empty.
    49  	Endpoint string
    50  	// URL contains the parsed dial target with an optional default scheme added
    51  	// to it if the original dial target contained no scheme or contained an
    52  	// unregistered scheme. Any query params specified in the original dial
    53  	// target can be accessed from here.
    54  	URL url.URL
    55  }
    56  
    57  func (t *Target) key() targetKey {
    58  	return targetKey{
    59  		Scheme:    t.Scheme,
    60  		Authority: t.Authority,
    61  		Endpoint:  t.Endpoint,
    62  	}
    63  }
    64  
    65  type targetKey Target
    66  
    67  func (k targetKey) String() string {
    68  	// Only used by tests.
    69  	return fmt.Sprintf("%s|%s|%s", k.Scheme, k.Authority, k.Endpoint)
    70  }
    71  
    72  // ParseTarget uses RFC 3986 semantics to parse the given target into a
    73  // resolver.Target struct containing scheme, authority and endpoint. Query
    74  // params are stripped from the endpoint.
    75  //
    76  // If target is not a valid scheme://authority/endpoint as specified in
    77  // https://github.com/grpc/grpc/blob/master/doc/naming.md,
    78  // it returns {Endpoint: target}.
    79  // Code borrowed from https://github.com/grpc/grpc-go/blob/v1.48.0/clientconn.go#L1619
    80  // See https://github.com/grpc/grpc-go/pull/4817
    81  func ParseTarget(target string) Target {
    82  	parsedTarget, err := parseTarget(target)
    83  	if err == nil && parsedTarget.Scheme != "" {
    84  		return parsedTarget
    85  	}
    86  
    87  	// We are here because the user's dial target did not contain a scheme or
    88  	// specified an unregistered scheme. We should fallback to the default
    89  	// scheme, except when a custom dialer is specified in which case, we should
    90  	// always use passthrough scheme.
    91  	defScheme := GetDefaultScheme()
    92  	canonicalTarget := defScheme + ":///" + target
    93  
    94  	parsedTarget, err = parseTarget(canonicalTarget)
    95  	if err != nil {
    96  		return Target{
    97  			Endpoint: target,
    98  			URL: url.URL{
    99  				Path: target,
   100  			},
   101  		}
   102  	}
   103  	parsedTarget.Scheme = "" // trim scheme
   104  	parsedTarget.URL.Scheme = ""
   105  	return parsedTarget
   106  }
   107  
   108  // parseTarget uses RFC 3986 semantics to parse the given target into a
   109  // resolver.Target struct containing scheme, authority and endpoint. Query
   110  // params are stripped from the endpoint.
   111  func parseTarget(target string) (Target, error) {
   112  	u, err := url.Parse(target)
   113  	if err != nil {
   114  		return Target{}, err
   115  	}
   116  	// For targets of the form "[scheme]://[authority]/endpoint, the endpoint
   117  	// value returned from url.Parse() contains a leading "/". Although this is
   118  	// in accordance with RFC 3986, we do not want to break existing resolver
   119  	// implementations which expect the endpoint without the leading "/". So, we
   120  	// end up stripping the leading "/" here. But this will result in an
   121  	// incorrect parsing for something like "unix:///path/to/socket". Since we
   122  	// own the "unix" resolver, we can workaround in the unix resolver by using
   123  	// the `URL` field instead of the `Endpoint` field.
   124  	endpoint := u.Path
   125  	if endpoint == "" {
   126  		endpoint = u.Opaque
   127  	}
   128  	endpoint = strings.TrimPrefix(endpoint, "/")
   129  	return Target{
   130  		Scheme:    u.Scheme,
   131  		Authority: u.Host,
   132  		Endpoint:  endpoint,
   133  		URL:       *u,
   134  	}, nil
   135  }