github.com/cloudwego/kitex@v0.9.0/pkg/remote/trans/nphttp2/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 * This file may have been modified by CloudWeGo authors. All CloudWeGo 18 * Modifications are Copyright 2021 CloudWeGo Authors. 19 */ 20 21 // Package metadata define the structure of the metadata supported by gRPC library. 22 // Please refer to https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md 23 // for more information about custom-metadata. 24 package metadata 25 26 import ( 27 "context" 28 "fmt" 29 "strings" 30 ) 31 32 // DecodeKeyValue returns k, v, nil. 33 // 34 // Deprecated: use k and v directly instead. 35 func DecodeKeyValue(k, v string) (string, string, error) { 36 return k, v, nil 37 } 38 39 // MD is a mapping from metadata keys to values. Users should use the following 40 // two convenience functions New and Pairs to generate MD. 41 type MD map[string][]string 42 43 // New creates an MD from a given key-value map. 44 // 45 // Only the following ASCII characters are allowed in keys: 46 // - digits: 0-9 47 // - uppercase letters: A-Z (normalized to lower) 48 // - lowercase letters: a-z 49 // - special characters: -_. 50 // 51 // Uppercase letters are automatically converted to lowercase. 52 // 53 // Keys beginning with "grpc-" are reserved for grpc-internal use only and may 54 // result in errors if set in metadata. 55 func New(m map[string]string) MD { 56 md := MD{} 57 for k, val := range m { 58 key := strings.ToLower(k) 59 md[key] = append(md[key], val) 60 } 61 return md 62 } 63 64 // Pairs returns an MD formed by the mapping of key, value ... 65 // Pairs panics if len(kv) is odd. 66 // 67 // Only the following ASCII characters are allowed in keys: 68 // - digits: 0-9 69 // - uppercase letters: A-Z (normalized to lower) 70 // - lowercase letters: a-z 71 // - special characters: -_. 72 // 73 // Uppercase letters are automatically converted to lowercase. 74 // 75 // Keys beginning with "grpc-" are reserved for grpc-internal use only and may 76 // result in errors if set in metadata. 77 func Pairs(kv ...string) MD { 78 if len(kv)%2 == 1 { 79 panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv))) 80 } 81 md := MD{} 82 var key string 83 for i, s := range kv { 84 if i%2 == 0 { 85 key = strings.ToLower(s) 86 continue 87 } 88 md[key] = append(md[key], s) 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 result := make(MD, len(md)) 101 for k, v := range md { 102 values := make([]string, len(v)) 103 copy(values, v) 104 result[k] = values 105 } 106 return result 107 } 108 109 // Get obtains the values for a given key. 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 func (md MD) Set(k string, vals ...string) { 117 if len(vals) == 0 { 118 return 119 } 120 k = strings.ToLower(k) 121 md[k] = vals 122 } 123 124 // Append adds the values to key k, not overwriting what was already stored at that key. 125 func (md MD) Append(k string, vals ...string) { 126 if len(vals) == 0 { 127 return 128 } 129 k = strings.ToLower(k) 130 md[k] = append(md[k], vals...) 131 } 132 133 // Join joins any number of mds into a single MD. 134 // The order of values for each key is determined by the order in which 135 // the mds containing those values are presented to Join. 136 func Join(mds ...MD) MD { 137 n := 0 138 for _, md := range mds { 139 n += len(md) 140 } 141 out := make(MD, n) 142 for _, md := range mds { 143 for k, v := range md { 144 out[k] = append(out[k], v...) 145 } 146 } 147 return out 148 } 149 150 // AppendMD appends other into md, merging values of the same key. 151 func AppendMD(md, other MD) MD { 152 if md == nil { 153 md = make(MD, len(other)) 154 } 155 for k, v := range other { 156 md[k] = append(md[k], v...) 157 } 158 return md 159 } 160 161 type ( 162 mdIncomingKey struct{} 163 mdOutgoingKey struct{} 164 ) 165 166 // NewIncomingContext creates a new context with incoming md attached. 167 func NewIncomingContext(ctx context.Context, md MD) context.Context { 168 return context.WithValue(ctx, mdIncomingKey{}, md) 169 } 170 171 // NewOutgoingContext creates a new context with outgoing md attached. If used 172 // in conjunction with AppendToOutgoingContext, NewOutgoingContext will 173 // overwrite any previously-appended metadata. 174 func NewOutgoingContext(ctx context.Context, md MD) context.Context { 175 return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md}) 176 } 177 178 // AppendToOutgoingContext returns a new context with the provided kv merged 179 // with any existing metadata in the context. Please refer to the 180 // documentation of Pairs for a description of kv. 181 func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context { 182 if len(kv)%2 == 1 { 183 panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len(kv))) 184 } 185 md, _ := ctx.Value(mdOutgoingKey{}).(rawMD) 186 added := make([][]string, len(md.added)+1) 187 copy(added, md.added) 188 added[len(added)-1] = make([]string, len(kv)) 189 copy(added[len(added)-1], kv) 190 return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md.md, added: added}) 191 } 192 193 // FromIncomingContext returns the incoming metadata in ctx if it exists. The 194 // returned MD should not be modified. Writing to it may cause races. 195 // Modification should be made to copies of the returned MD. 196 func FromIncomingContext(ctx context.Context) (md MD, ok bool) { 197 md, ok = ctx.Value(mdIncomingKey{}).(MD) 198 return 199 } 200 201 // FromOutgoingContextRaw returns the un-merged, intermediary contents 202 // of rawMD. Remember to perform strings.ToLower on the keys. The returned 203 // MD should not be modified. Writing to it may cause races. Modification 204 // should be made to copies of the returned MD. 205 // 206 // This is intended for gRPC-internal use ONLY. 207 func FromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) { 208 raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD) 209 if !ok { 210 return nil, nil, false 211 } 212 213 return raw.md, raw.added, true 214 } 215 216 // FromOutgoingContext returns the outgoing metadata in ctx if it exists. The 217 // returned MD should not be modified. Writing to it may cause races. 218 // Modification should be made to copies of the returned MD. 219 func FromOutgoingContext(ctx context.Context) (MD, bool) { 220 raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD) 221 if !ok { 222 return nil, false 223 } 224 225 mds := make([]MD, 0, len(raw.added)+1) 226 mds = append(mds, raw.md) 227 for _, vv := range raw.added { 228 mds = append(mds, Pairs(vv...)) 229 } 230 return Join(mds...), ok 231 } 232 233 type rawMD struct { 234 md MD 235 added [][]string 236 }