github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/xdsclient/xdsresource/name.go (about)

     1  /*
     2   *
     3   * Copyright 2021 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package xdsresource
    19  
    20  import (
    21  	"net/url"
    22  	"sort"
    23  	"strings"
    24  
    25  	"github.com/hxx258456/ccgo/grpc/internal/envconfig"
    26  )
    27  
    28  // Name contains the parsed component of an xDS resource name.
    29  //
    30  // An xDS resource name is in the format of
    31  // xdstp://[{authority}]/{resource type}/{id/*}?{context parameters}{#processing directive,*}
    32  //
    33  // See
    34  // https://github.com/cncf/xds/blob/main/proposals/TP1-xds-transport-next.md#uri-based-xds-resource-names
    35  // for details, and examples.
    36  type Name struct {
    37  	Scheme    string
    38  	Authority string
    39  	Type      string
    40  	ID        string
    41  
    42  	ContextParams map[string]string
    43  
    44  	processingDirective string
    45  }
    46  
    47  // ParseName splits the name and returns a struct representation of the Name.
    48  //
    49  // If the name isn't a valid new-style xDS name, field ID is set to the input.
    50  // Note that this is not an error, because we still support the old-style
    51  // resource names (those not starting with "xdstp:").
    52  //
    53  // The caller can tell if the parsing is successful by checking the returned
    54  // Scheme.
    55  func ParseName(name string) *Name {
    56  	if !envconfig.XDSFederation {
    57  		// Return "" scheme to use the default authority for the server.
    58  		return &Name{ID: name}
    59  	}
    60  	if !strings.Contains(name, "://") {
    61  		// Only the long form URL, with ://, is valid.
    62  		return &Name{ID: name}
    63  	}
    64  	parsed, err := url.Parse(name)
    65  	if err != nil {
    66  		return &Name{ID: name}
    67  	}
    68  
    69  	ret := &Name{
    70  		Scheme:    parsed.Scheme,
    71  		Authority: parsed.Host,
    72  	}
    73  	split := strings.SplitN(parsed.Path, "/", 3)
    74  	if len(split) < 3 {
    75  		// Path is in the format of "/type/id". There must be at least 3
    76  		// segments after splitting.
    77  		return &Name{ID: name}
    78  	}
    79  	ret.Type = split[1]
    80  	ret.ID = split[2]
    81  	if len(parsed.Query()) != 0 {
    82  		ret.ContextParams = make(map[string]string)
    83  		for k, vs := range parsed.Query() {
    84  			if len(vs) > 0 {
    85  				// We only keep one value of each key. Behavior for multiple values
    86  				// is undefined.
    87  				ret.ContextParams[k] = vs[0]
    88  			}
    89  		}
    90  	}
    91  	// TODO: processing directive (the part comes after "#" in the URL, stored
    92  	// in parsed.RawFragment) is kept but not processed. Add support for that
    93  	// when it's needed.
    94  	ret.processingDirective = parsed.RawFragment
    95  	return ret
    96  }
    97  
    98  // String returns a canonicalized string of name. The context parameters are
    99  // sorted by the keys.
   100  func (n *Name) String() string {
   101  	if n.Scheme == "" {
   102  		return n.ID
   103  	}
   104  
   105  	// Sort and build query.
   106  	keys := make([]string, 0, len(n.ContextParams))
   107  	for k := range n.ContextParams {
   108  		keys = append(keys, k)
   109  	}
   110  	sort.Strings(keys)
   111  	var pairs []string
   112  	for _, k := range keys {
   113  		pairs = append(pairs, strings.Join([]string{k, n.ContextParams[k]}, "="))
   114  	}
   115  	rawQuery := strings.Join(pairs, "&")
   116  
   117  	path := n.Type
   118  	if n.ID != "" {
   119  		path = path + "/" + n.ID
   120  	}
   121  
   122  	tempURL := &url.URL{
   123  		Scheme:      n.Scheme,
   124  		Host:        n.Authority,
   125  		Path:        path,
   126  		RawQuery:    rawQuery,
   127  		RawFragment: n.processingDirective,
   128  	}
   129  	return tempURL.String()
   130  }