gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

metadata.go (8558B)


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