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 }