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