metadata.go 8.4 KB

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