gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/metadata/metadata.go (about)

     1  /*
     2   *
     3   * Copyright 2014 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  
    19  // Package metadata define the structure of the metadata supported by gRPC library.
    20  // Please refer to https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
    21  // for more information about custom-metadata.
    22  package metadata // import "gitee.com/ks-custle/core-gm/grpc/metadata"
    23  
    24  import (
    25  	"context"
    26  	"fmt"
    27  	"strings"
    28  )
    29  
    30  // DecodeKeyValue returns k, v, nil.
    31  //
    32  // Deprecated: use k and v directly instead.
    33  func DecodeKeyValue(k, v string) (string, string, error) {
    34  	return k, v, nil
    35  }
    36  
    37  // MD is a mapping from metadata keys to values. Users should use the following
    38  // two convenience functions New and Pairs to generate MD.
    39  type MD map[string][]string
    40  
    41  // New creates an MD from a given key-value map.
    42  //
    43  // Only the following ASCII characters are allowed in keys:
    44  //   - digits: 0-9
    45  //   - uppercase letters: A-Z (normalized to lower)
    46  //   - lowercase letters: a-z
    47  //   - special characters: -_.
    48  //
    49  // Uppercase letters are automatically converted to lowercase.
    50  //
    51  // Keys beginning with "grpc-" are reserved for grpc-internal use only and may
    52  // result in errors if set in metadata.
    53  func New(m map[string]string) MD {
    54  	md := MD{}
    55  	for k, val := range m {
    56  		key := strings.ToLower(k)
    57  		md[key] = append(md[key], val)
    58  	}
    59  	return md
    60  }
    61  
    62  // Pairs returns an MD formed by the mapping of key, value ...
    63  // Pairs panics if len(kv) is odd.
    64  //
    65  // Only the following ASCII characters are allowed in keys:
    66  //   - digits: 0-9
    67  //   - uppercase letters: A-Z (normalized to lower)
    68  //   - lowercase letters: a-z
    69  //   - special characters: -_.
    70  //
    71  // Uppercase letters are automatically converted to lowercase.
    72  //
    73  // Keys beginning with "grpc-" are reserved for grpc-internal use only and may
    74  // result in errors if set in metadata.
    75  func Pairs(kv ...string) MD {
    76  	if len(kv)%2 == 1 {
    77  		panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv)))
    78  	}
    79  	md := MD{}
    80  	for i := 0; i < len(kv); i += 2 {
    81  		key := strings.ToLower(kv[i])
    82  		md[key] = append(md[key], kv[i+1])
    83  	}
    84  	return md
    85  }
    86  
    87  // Len returns the number of items in md.
    88  func (md MD) Len() int {
    89  	return len(md)
    90  }
    91  
    92  // Copy returns a copy of md.
    93  func (md MD) Copy() MD {
    94  	return Join(md)
    95  }
    96  
    97  // Get obtains the values for a given key.
    98  //
    99  // k is converted to lowercase before searching in md.
   100  func (md MD) Get(k string) []string {
   101  	k = strings.ToLower(k)
   102  	return md[k]
   103  }
   104  
   105  // Set sets the value of a given key with a slice of values.
   106  //
   107  // k is converted to lowercase before storing in md.
   108  func (md MD) Set(k string, vals ...string) {
   109  	if len(vals) == 0 {
   110  		return
   111  	}
   112  	k = strings.ToLower(k)
   113  	md[k] = vals
   114  }
   115  
   116  // Append adds the values to key k, not overwriting what was already stored at
   117  // that key.
   118  //
   119  // k is converted to lowercase before storing in md.
   120  func (md MD) Append(k string, vals ...string) {
   121  	if len(vals) == 0 {
   122  		return
   123  	}
   124  	k = strings.ToLower(k)
   125  	md[k] = append(md[k], vals...)
   126  }
   127  
   128  // Delete removes the values for a given key k which is converted to lowercase
   129  // before removing it from md.
   130  func (md MD) Delete(k string) {
   131  	k = strings.ToLower(k)
   132  	delete(md, k)
   133  }
   134  
   135  // Join joins any number of mds into a single MD.
   136  //
   137  // The order of values for each key is determined by the order in which the mds
   138  // containing those values are presented to Join.
   139  func Join(mds ...MD) MD {
   140  	out := MD{}
   141  	for _, md := range mds {
   142  		for k, v := range md {
   143  			out[k] = append(out[k], v...)
   144  		}
   145  	}
   146  	return out
   147  }
   148  
   149  type mdIncomingKey struct{}
   150  type mdOutgoingKey struct{}
   151  
   152  // NewIncomingContext creates a new context with incoming md attached.
   153  func NewIncomingContext(ctx context.Context, md MD) context.Context {
   154  	return context.WithValue(ctx, mdIncomingKey{}, md)
   155  }
   156  
   157  // NewOutgoingContext creates a new context with outgoing md attached. If used
   158  // in conjunction with AppendToOutgoingContext, NewOutgoingContext will
   159  // overwrite any previously-appended metadata.
   160  func NewOutgoingContext(ctx context.Context, md MD) context.Context {
   161  	return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md})
   162  }
   163  
   164  // AppendToOutgoingContext returns a new context with the provided kv merged
   165  // with any existing metadata in the context. Please refer to the documentation
   166  // of Pairs for a description of kv.
   167  func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context {
   168  	if len(kv)%2 == 1 {
   169  		panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len(kv)))
   170  	}
   171  	md, _ := ctx.Value(mdOutgoingKey{}).(rawMD)
   172  	added := make([][]string, len(md.added)+1)
   173  	copy(added, md.added)
   174  	added[len(added)-1] = make([]string, len(kv))
   175  	copy(added[len(added)-1], kv)
   176  	return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md.md, added: added})
   177  }
   178  
   179  // FromIncomingContext returns the incoming metadata in ctx if it exists.
   180  //
   181  // All keys in the returned MD are lowercase.
   182  func FromIncomingContext(ctx context.Context) (MD, bool) {
   183  	md, ok := ctx.Value(mdIncomingKey{}).(MD)
   184  	if !ok {
   185  		return nil, false
   186  	}
   187  	out := MD{}
   188  	for k, v := range md {
   189  		// We need to manually convert all keys to lower case, because MD is a
   190  		// map, and there's no guarantee that the MD attached to the context is
   191  		// created using our helper functions.
   192  		key := strings.ToLower(k)
   193  		out[key] = v
   194  	}
   195  	return out, true
   196  }
   197  
   198  // FromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD.
   199  //
   200  // Remember to perform strings.ToLower on the keys, for both the returned MD (MD
   201  // is a map, there's no guarantee it's created using our helper functions) and
   202  // the extra kv pairs (AppendToOutgoingContext doesn't turn them into
   203  // lowercase).
   204  //
   205  // This is intended for gRPC-internal use ONLY. Users should use
   206  // FromOutgoingContext instead.
   207  func FromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) {
   208  	raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
   209  	if !ok {
   210  		return nil, nil, false
   211  	}
   212  
   213  	return raw.md, raw.added, true
   214  }
   215  
   216  // FromOutgoingContext returns the outgoing metadata in ctx if it exists.
   217  //
   218  // All keys in the returned MD are lowercase.
   219  func FromOutgoingContext(ctx context.Context) (MD, bool) {
   220  	raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
   221  	if !ok {
   222  		return nil, false
   223  	}
   224  
   225  	out := MD{}
   226  	for k, v := range raw.md {
   227  		// We need to manually convert all keys to lower case, because MD is a
   228  		// map, and there's no guarantee that the MD attached to the context is
   229  		// created using our helper functions.
   230  		key := strings.ToLower(k)
   231  		out[key] = v
   232  	}
   233  	for _, added := range raw.added {
   234  		if len(added)%2 == 1 {
   235  			panic(fmt.Sprintf("metadata: FromOutgoingContext got an odd number of input pairs for metadata: %d", len(added)))
   236  		}
   237  
   238  		for i := 0; i < len(added); i += 2 {
   239  			key := strings.ToLower(added[i])
   240  			out[key] = append(out[key], added[i+1])
   241  		}
   242  	}
   243  	return out, ok
   244  }
   245  
   246  type rawMD struct {
   247  	md    MD
   248  	added [][]string
   249  }