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 }