github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/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 "github.com/hxx258456/ccgo/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 // Uppercase letters are automatically converted to lowercase. 49 // 50 // Keys beginning with "grpc-" are reserved for grpc-internal use only and may 51 // result in errors if set in metadata. 52 func New(m map[string]string) MD { 53 md := MD{} 54 for k, val := range m { 55 key := strings.ToLower(k) 56 md[key] = append(md[key], val) 57 } 58 return md 59 } 60 61 // Pairs returns an MD formed by the mapping of key, value ... 62 // Pairs panics if len(kv) is odd. 63 // 64 // Only the following ASCII characters are allowed in keys: 65 // - digits: 0-9 66 // - uppercase letters: A-Z (normalized to lower) 67 // - lowercase letters: a-z 68 // - special characters: -_. 69 // Uppercase letters are automatically converted to lowercase. 70 // 71 // Keys beginning with "grpc-" are reserved for grpc-internal use only and may 72 // result in errors if set in metadata. 73 func Pairs(kv ...string) MD { 74 if len(kv)%2 == 1 { 75 panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv))) 76 } 77 md := MD{} 78 for i := 0; i < len(kv); i += 2 { 79 key := strings.ToLower(kv[i]) 80 md[key] = append(md[key], kv[i+1]) 81 } 82 return md 83 } 84 85 // Len returns the number of items in md. 86 func (md MD) Len() int { 87 return len(md) 88 } 89 90 // Copy returns a copy of md. 91 func (md MD) Copy() MD { 92 return Join(md) 93 } 94 95 // Get obtains the values for a given key. 96 // 97 // k is converted to lowercase before searching in md. 98 func (md MD) Get(k string) []string { 99 k = strings.ToLower(k) 100 return md[k] 101 } 102 103 // Set sets the value of a given key with a slice of values. 104 // 105 // k is converted to lowercase before storing in md. 106 func (md MD) Set(k string, vals ...string) { 107 if len(vals) == 0 { 108 return 109 } 110 k = strings.ToLower(k) 111 md[k] = vals 112 } 113 114 // Append adds the values to key k, not overwriting what was already stored at 115 // that key. 116 // 117 // k is converted to lowercase before storing in md. 118 func (md MD) Append(k string, vals ...string) { 119 if len(vals) == 0 { 120 return 121 } 122 k = strings.ToLower(k) 123 md[k] = append(md[k], vals...) 124 } 125 126 // Delete removes the values for a given key k which is converted to lowercase 127 // before removing it from md. 128 func (md MD) Delete(k string) { 129 k = strings.ToLower(k) 130 delete(md, k) 131 } 132 133 // Join joins any number of mds into a single MD. 134 // 135 // The order of values for each key is determined by the order in which the mds 136 // containing those values are presented to Join. 137 func Join(mds ...MD) MD { 138 out := MD{} 139 for _, md := range mds { 140 for k, v := range md { 141 out[k] = append(out[k], v...) 142 } 143 } 144 return out 145 } 146 147 type mdIncomingKey struct{} 148 type mdOutgoingKey struct{} 149 150 // NewIncomingContext creates a new context with incoming md attached. 151 func NewIncomingContext(ctx context.Context, md MD) context.Context { 152 return context.WithValue(ctx, mdIncomingKey{}, md) 153 } 154 155 // NewOutgoingContext creates a new context with outgoing md attached. If used 156 // in conjunction with AppendToOutgoingContext, NewOutgoingContext will 157 // overwrite any previously-appended metadata. 158 func NewOutgoingContext(ctx context.Context, md MD) context.Context { 159 return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md}) 160 } 161 162 // AppendToOutgoingContext returns a new context with the provided kv merged 163 // with any existing metadata in the context. Please refer to the documentation 164 // of Pairs for a description of kv. 165 func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context { 166 if len(kv)%2 == 1 { 167 panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len(kv))) 168 } 169 md, _ := ctx.Value(mdOutgoingKey{}).(rawMD) 170 added := make([][]string, len(md.added)+1) 171 copy(added, md.added) 172 added[len(added)-1] = make([]string, len(kv)) 173 copy(added[len(added)-1], kv) 174 return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md.md, added: added}) 175 } 176 177 // FromIncomingContext returns the incoming metadata in ctx if it exists. 178 // 179 // All keys in the returned MD are lowercase. 180 func FromIncomingContext(ctx context.Context) (MD, bool) { 181 md, ok := ctx.Value(mdIncomingKey{}).(MD) 182 if !ok { 183 return nil, false 184 } 185 out := MD{} 186 for k, v := range md { 187 // We need to manually convert all keys to lower case, because MD is a 188 // map, and there's no guarantee that the MD attached to the context is 189 // created using our helper functions. 190 key := strings.ToLower(k) 191 out[key] = v 192 } 193 return out, true 194 } 195 196 // FromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD. 197 // 198 // Remember to perform strings.ToLower on the keys, for both the returned MD (MD 199 // is a map, there's no guarantee it's created using our helper functions) and 200 // the extra kv pairs (AppendToOutgoingContext doesn't turn them into 201 // lowercase). 202 // 203 // This is intended for gRPC-internal use ONLY. Users should use 204 // FromOutgoingContext instead. 205 func FromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) { 206 raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD) 207 if !ok { 208 return nil, nil, false 209 } 210 211 return raw.md, raw.added, true 212 } 213 214 // FromOutgoingContext returns the outgoing metadata in ctx if it exists. 215 // 216 // All keys in the returned MD are lowercase. 217 func FromOutgoingContext(ctx context.Context) (MD, bool) { 218 raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD) 219 if !ok { 220 return nil, false 221 } 222 223 out := MD{} 224 for k, v := range raw.md { 225 // We need to manually convert all keys to lower case, because MD is a 226 // map, and there's no guarantee that the MD attached to the context is 227 // created using our helper functions. 228 key := strings.ToLower(k) 229 out[key] = v 230 } 231 for _, added := range raw.added { 232 if len(added)%2 == 1 { 233 panic(fmt.Sprintf("metadata: FromOutgoingContext got an odd number of input pairs for metadata: %d", len(added))) 234 } 235 236 for i := 0; i < len(added); i += 2 { 237 key := strings.ToLower(added[i]) 238 out[key] = append(out[key], added[i+1]) 239 } 240 } 241 return out, ok 242 } 243 244 type rawMD struct { 245 md MD 246 added [][]string 247 }