...

Source file src/google.golang.org/grpc/metadata/metadata.go

Documentation: google.golang.org/grpc/metadata

     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  // String implements the Stringer interface for pretty-printing a MD.
    94  // Ordering of the values is non-deterministic as it ranges over a map.
    95  func (md MD) String() string {
    96  	var sb strings.Builder
    97  	fmt.Fprintf(&sb, "MD{")
    98  	for k, v := range md {
    99  		if sb.Len() > 3 {
   100  			fmt.Fprintf(&sb, ", ")
   101  		}
   102  		fmt.Fprintf(&sb, "%s=[%s]", k, strings.Join(v, ", "))
   103  	}
   104  	fmt.Fprintf(&sb, "}")
   105  	return sb.String()
   106  }
   107  
   108  // Len returns the number of items in md.
   109  func (md MD) Len() int {
   110  	return len(md)
   111  }
   112  
   113  // Copy returns a copy of md.
   114  func (md MD) Copy() MD {
   115  	out := make(MD, len(md))
   116  	for k, v := range md {
   117  		out[k] = copyOf(v)
   118  	}
   119  	return out
   120  }
   121  
   122  // Get obtains the values for a given key.
   123  //
   124  // k is converted to lowercase before searching in md.
   125  func (md MD) Get(k string) []string {
   126  	k = strings.ToLower(k)
   127  	return md[k]
   128  }
   129  
   130  // Set sets the value of a given key with a slice of values.
   131  //
   132  // k is converted to lowercase before storing in md.
   133  func (md MD) Set(k string, vals ...string) {
   134  	if len(vals) == 0 {
   135  		return
   136  	}
   137  	k = strings.ToLower(k)
   138  	md[k] = vals
   139  }
   140  
   141  // Append adds the values to key k, not overwriting what was already stored at
   142  // that key.
   143  //
   144  // k is converted to lowercase before storing in md.
   145  func (md MD) Append(k string, vals ...string) {
   146  	if len(vals) == 0 {
   147  		return
   148  	}
   149  	k = strings.ToLower(k)
   150  	md[k] = append(md[k], vals...)
   151  }
   152  
   153  // Delete removes the values for a given key k which is converted to lowercase
   154  // before removing it from md.
   155  func (md MD) Delete(k string) {
   156  	k = strings.ToLower(k)
   157  	delete(md, k)
   158  }
   159  
   160  // Join joins any number of mds into a single MD.
   161  //
   162  // The order of values for each key is determined by the order in which the mds
   163  // containing those values are presented to Join.
   164  func Join(mds ...MD) MD {
   165  	out := MD{}
   166  	for _, md := range mds {
   167  		for k, v := range md {
   168  			out[k] = append(out[k], v...)
   169  		}
   170  	}
   171  	return out
   172  }
   173  
   174  type mdIncomingKey struct{}
   175  type mdOutgoingKey struct{}
   176  
   177  // NewIncomingContext creates a new context with incoming md attached. md must
   178  // not be modified after calling this function.
   179  func NewIncomingContext(ctx context.Context, md MD) context.Context {
   180  	return context.WithValue(ctx, mdIncomingKey{}, md)
   181  }
   182  
   183  // NewOutgoingContext creates a new context with outgoing md attached. If used
   184  // in conjunction with AppendToOutgoingContext, NewOutgoingContext will
   185  // overwrite any previously-appended metadata. md must not be modified after
   186  // calling this function.
   187  func NewOutgoingContext(ctx context.Context, md MD) context.Context {
   188  	return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md})
   189  }
   190  
   191  // AppendToOutgoingContext returns a new context with the provided kv merged
   192  // with any existing metadata in the context. Please refer to the documentation
   193  // of Pairs for a description of kv.
   194  func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context {
   195  	if len(kv)%2 == 1 {
   196  		panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len(kv)))
   197  	}
   198  	md, _ := ctx.Value(mdOutgoingKey{}).(rawMD)
   199  	added := make([][]string, len(md.added)+1)
   200  	copy(added, md.added)
   201  	kvCopy := make([]string, 0, len(kv))
   202  	for i := 0; i < len(kv); i += 2 {
   203  		kvCopy = append(kvCopy, strings.ToLower(kv[i]), kv[i+1])
   204  	}
   205  	added[len(added)-1] = kvCopy
   206  	return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md.md, added: added})
   207  }
   208  
   209  // FromIncomingContext returns the incoming metadata in ctx if it exists.
   210  //
   211  // All keys in the returned MD are lowercase.
   212  func FromIncomingContext(ctx context.Context) (MD, bool) {
   213  	md, ok := ctx.Value(mdIncomingKey{}).(MD)
   214  	if !ok {
   215  		return nil, false
   216  	}
   217  	out := make(MD, len(md))
   218  	for k, v := range md {
   219  		// We need to manually convert all keys to lower case, because MD is a
   220  		// map, and there's no guarantee that the MD attached to the context is
   221  		// created using our helper functions.
   222  		key := strings.ToLower(k)
   223  		out[key] = copyOf(v)
   224  	}
   225  	return out, true
   226  }
   227  
   228  // ValueFromIncomingContext returns the metadata value corresponding to the metadata
   229  // key from the incoming metadata if it exists. Keys are matched in a case insensitive
   230  // manner.
   231  //
   232  // # Experimental
   233  //
   234  // Notice: This API is EXPERIMENTAL and may be changed or removed in a
   235  // later release.
   236  func ValueFromIncomingContext(ctx context.Context, key string) []string {
   237  	md, ok := ctx.Value(mdIncomingKey{}).(MD)
   238  	if !ok {
   239  		return nil
   240  	}
   241  
   242  	if v, ok := md[key]; ok {
   243  		return copyOf(v)
   244  	}
   245  	for k, v := range md {
   246  		// Case insenitive comparison: MD is a map, and there's no guarantee
   247  		// that the MD attached to the context is created using our helper
   248  		// functions.
   249  		if strings.EqualFold(k, key) {
   250  			return copyOf(v)
   251  		}
   252  	}
   253  	return nil
   254  }
   255  
   256  func copyOf(v []string) []string {
   257  	vals := make([]string, len(v))
   258  	copy(vals, v)
   259  	return vals
   260  }
   261  
   262  // fromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD.
   263  //
   264  // Remember to perform strings.ToLower on the keys, for both the returned MD (MD
   265  // is a map, there's no guarantee it's created using our helper functions) and
   266  // the extra kv pairs (AppendToOutgoingContext doesn't turn them into
   267  // lowercase).
   268  func fromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) {
   269  	raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
   270  	if !ok {
   271  		return nil, nil, false
   272  	}
   273  
   274  	return raw.md, raw.added, true
   275  }
   276  
   277  // FromOutgoingContext returns the outgoing metadata in ctx if it exists.
   278  //
   279  // All keys in the returned MD are lowercase.
   280  func FromOutgoingContext(ctx context.Context) (MD, bool) {
   281  	raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
   282  	if !ok {
   283  		return nil, false
   284  	}
   285  
   286  	mdSize := len(raw.md)
   287  	for i := range raw.added {
   288  		mdSize += len(raw.added[i]) / 2
   289  	}
   290  
   291  	out := make(MD, mdSize)
   292  	for k, v := range raw.md {
   293  		// We need to manually convert all keys to lower case, because MD is a
   294  		// map, and there's no guarantee that the MD attached to the context is
   295  		// created using our helper functions.
   296  		key := strings.ToLower(k)
   297  		out[key] = copyOf(v)
   298  	}
   299  	for _, added := range raw.added {
   300  		if len(added)%2 == 1 {
   301  			panic(fmt.Sprintf("metadata: FromOutgoingContext got an odd number of input pairs for metadata: %d", len(added)))
   302  		}
   303  
   304  		for i := 0; i < len(added); i += 2 {
   305  			key := strings.ToLower(added[i])
   306  			out[key] = append(out[key], added[i+1])
   307  		}
   308  	}
   309  	return out, ok
   310  }
   311  
   312  type rawMD struct {
   313  	md    MD
   314  	added [][]string
   315  }
   316  

View as plain text