google.golang.org/grpc@v1.62.1/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 "google.golang.org/grpc/metadata"
    23  
    24  import (
    25  	"context"
    26  	"fmt"
    27  	"strings"
    28  
    29  	"google.golang.org/grpc/internal"
    30  )
    31  
    32  func init() {
    33  	internal.FromOutgoingContextRaw = fromOutgoingContextRaw
    34  }
    35  
    36  // DecodeKeyValue returns k, v, nil.
    37  //
    38  // Deprecated: use k and v directly instead.
    39  func DecodeKeyValue(k, v string) (string, string, error) {
    40  	return k, v, nil
    41  }
    42  
    43  // MD is a mapping from metadata keys to values. Users should use the following
    44  // two convenience functions New and Pairs to generate MD.
    45  type MD map[string][]string
    46  
    47  // New creates an MD from a given key-value map.
    48  //
    49  // Only the following ASCII characters are allowed in keys:
    50  //   - digits: 0-9
    51  //   - uppercase letters: A-Z (normalized to lower)
    52  //   - lowercase letters: a-z
    53  //   - special characters: -_.
    54  //
    55  // Uppercase letters are automatically converted to lowercase.
    56  //
    57  // Keys beginning with "grpc-" are reserved for grpc-internal use only and may
    58  // result in errors if set in metadata.
    59  func New(m map[string]string) MD {
    60  	md := make(MD, len(m))
    61  	for k, val := range m {
    62  		key := strings.ToLower(k)
    63  		md[key] = append(md[key], val)
    64  	}
    65  	return md
    66  }
    67  
    68  // Pairs returns an MD formed by the mapping of key, value ...
    69  // Pairs panics if len(kv) is odd.
    70  //
    71  // Only the following ASCII characters are allowed in keys:
    72  //   - digits: 0-9
    73  //   - uppercase letters: A-Z (normalized to lower)
    74  //   - lowercase letters: a-z
    75  //   - special characters: -_.
    76  //
    77  // Uppercase letters are automatically converted to lowercase.
    78  //
    79  // Keys beginning with "grpc-" are reserved for grpc-internal use only and may
    80  // result in errors if set in metadata.
    81  func Pairs(kv ...string) MD {
    82  	if len(kv)%2 == 1 {
    83  		panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv)))
    84  	}
    85  	md := make(MD, len(kv)/2)
    86  	for i := 0; i < len(kv); i += 2 {
    87  		key := strings.ToLower(kv[i])
    88  		md[key] = append(md[key], kv[i+1])
    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  	out := make(MD, len(md))
   101  	for k, v := range md {
   102  		out[k] = copyOf(v)
   103  	}
   104  	return out
   105  }
   106  
   107  // Get obtains the values for a given key.
   108  //
   109  // k is converted to lowercase before searching in md.
   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  //
   117  // k is converted to lowercase before storing in md.
   118  func (md MD) Set(k string, vals ...string) {
   119  	if len(vals) == 0 {
   120  		return
   121  	}
   122  	k = strings.ToLower(k)
   123  	md[k] = vals
   124  }
   125  
   126  // Append adds the values to key k, not overwriting what was already stored at
   127  // that key.
   128  //
   129  // k is converted to lowercase before storing in md.
   130  func (md MD) Append(k string, vals ...string) {
   131  	if len(vals) == 0 {
   132  		return
   133  	}
   134  	k = strings.ToLower(k)
   135  	md[k] = append(md[k], vals...)
   136  }
   137  
   138  // Delete removes the values for a given key k which is converted to lowercase
   139  // before removing it from md.
   140  func (md MD) Delete(k string) {
   141  	k = strings.ToLower(k)
   142  	delete(md, k)
   143  }
   144  
   145  // Join joins any number of mds into a single MD.
   146  //
   147  // The order of values for each key is determined by the order in which the mds
   148  // containing those values are presented to Join.
   149  func Join(mds ...MD) MD {
   150  	out := MD{}
   151  	for _, md := range mds {
   152  		for k, v := range md {
   153  			out[k] = append(out[k], v...)
   154  		}
   155  	}
   156  	return out
   157  }
   158  
   159  type mdIncomingKey struct{}
   160  type mdOutgoingKey struct{}
   161  
   162  // NewIncomingContext creates a new context with incoming md attached. md must
   163  // not be modified after calling this function.
   164  func NewIncomingContext(ctx context.Context, md MD) context.Context {
   165  	return context.WithValue(ctx, mdIncomingKey{}, md)
   166  }
   167  
   168  // NewOutgoingContext creates a new context with outgoing md attached. If used
   169  // in conjunction with AppendToOutgoingContext, NewOutgoingContext will
   170  // overwrite any previously-appended metadata. md must not be modified after
   171  // calling this function.
   172  func NewOutgoingContext(ctx context.Context, md MD) context.Context {
   173  	return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md})
   174  }
   175  
   176  // AppendToOutgoingContext returns a new context with the provided kv merged
   177  // with any existing metadata in the context. Please refer to the documentation
   178  // of Pairs for a description of kv.
   179  func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context {
   180  	if len(kv)%2 == 1 {
   181  		panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len(kv)))
   182  	}
   183  	md, _ := ctx.Value(mdOutgoingKey{}).(rawMD)
   184  	added := make([][]string, len(md.added)+1)
   185  	copy(added, md.added)
   186  	kvCopy := make([]string, 0, len(kv))
   187  	for i := 0; i < len(kv); i += 2 {
   188  		kvCopy = append(kvCopy, strings.ToLower(kv[i]), kv[i+1])
   189  	}
   190  	added[len(added)-1] = kvCopy
   191  	return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md.md, added: added})
   192  }
   193  
   194  // FromIncomingContext returns the incoming metadata in ctx if it exists.
   195  //
   196  // All keys in the returned MD are lowercase.
   197  func FromIncomingContext(ctx context.Context) (MD, bool) {
   198  	md, ok := ctx.Value(mdIncomingKey{}).(MD)
   199  	if !ok {
   200  		return nil, false
   201  	}
   202  	out := make(MD, len(md))
   203  	for k, v := range md {
   204  		// We need to manually convert all keys to lower case, because MD is a
   205  		// map, and there's no guarantee that the MD attached to the context is
   206  		// created using our helper functions.
   207  		key := strings.ToLower(k)
   208  		out[key] = copyOf(v)
   209  	}
   210  	return out, true
   211  }
   212  
   213  // ValueFromIncomingContext returns the metadata value corresponding to the metadata
   214  // key from the incoming metadata if it exists. Keys are matched in a case insensitive
   215  // manner.
   216  //
   217  // # Experimental
   218  //
   219  // Notice: This API is EXPERIMENTAL and may be changed or removed in a
   220  // later release.
   221  func ValueFromIncomingContext(ctx context.Context, key string) []string {
   222  	md, ok := ctx.Value(mdIncomingKey{}).(MD)
   223  	if !ok {
   224  		return nil
   225  	}
   226  
   227  	if v, ok := md[key]; ok {
   228  		return copyOf(v)
   229  	}
   230  	for k, v := range md {
   231  		// Case insenitive comparison: MD is a map, and there's no guarantee
   232  		// that the MD attached to the context is created using our helper
   233  		// functions.
   234  		if strings.EqualFold(k, key) {
   235  			return copyOf(v)
   236  		}
   237  	}
   238  	return nil
   239  }
   240  
   241  func copyOf(v []string) []string {
   242  	vals := make([]string, len(v))
   243  	copy(vals, v)
   244  	return vals
   245  }
   246  
   247  // fromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD.
   248  //
   249  // Remember to perform strings.ToLower on the keys, for both the returned MD (MD
   250  // is a map, there's no guarantee it's created using our helper functions) and
   251  // the extra kv pairs (AppendToOutgoingContext doesn't turn them into
   252  // lowercase).
   253  func fromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) {
   254  	raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
   255  	if !ok {
   256  		return nil, nil, false
   257  	}
   258  
   259  	return raw.md, raw.added, true
   260  }
   261  
   262  // FromOutgoingContext returns the outgoing metadata in ctx if it exists.
   263  //
   264  // All keys in the returned MD are lowercase.
   265  func FromOutgoingContext(ctx context.Context) (MD, bool) {
   266  	raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
   267  	if !ok {
   268  		return nil, false
   269  	}
   270  
   271  	mdSize := len(raw.md)
   272  	for i := range raw.added {
   273  		mdSize += len(raw.added[i]) / 2
   274  	}
   275  
   276  	out := make(MD, mdSize)
   277  	for k, v := range raw.md {
   278  		// We need to manually convert all keys to lower case, because MD is a
   279  		// map, and there's no guarantee that the MD attached to the context is
   280  		// created using our helper functions.
   281  		key := strings.ToLower(k)
   282  		out[key] = copyOf(v)
   283  	}
   284  	for _, added := range raw.added {
   285  		if len(added)%2 == 1 {
   286  			panic(fmt.Sprintf("metadata: FromOutgoingContext got an odd number of input pairs for metadata: %d", len(added)))
   287  		}
   288  
   289  		for i := 0; i < len(added); i += 2 {
   290  			key := strings.ToLower(added[i])
   291  			out[key] = append(out[key], added[i+1])
   292  		}
   293  	}
   294  	return out, ok
   295  }
   296  
   297  type rawMD struct {
   298  	md    MD
   299  	added [][]string
   300  }