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