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