metadata.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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. md must
  142. // not be modified after calling this function.
  143. func NewIncomingContext(ctx context.Context, md MD) context.Context {
  144. return context.WithValue(ctx, mdIncomingKey{}, md)
  145. }
  146. // NewOutgoingContext creates a new context with outgoing md attached. If used
  147. // in conjunction with AppendToOutgoingContext, NewOutgoingContext will
  148. // overwrite any previously-appended metadata. md must not be modified after
  149. // calling this function.
  150. func NewOutgoingContext(ctx context.Context, md MD) context.Context {
  151. return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md})
  152. }
  153. // AppendToOutgoingContext returns a new context with the provided kv merged
  154. // with any existing metadata in the context. Please refer to the documentation
  155. // of Pairs for a description of kv.
  156. func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context {
  157. if len(kv)%2 == 1 {
  158. panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len(kv)))
  159. }
  160. md, _ := ctx.Value(mdOutgoingKey{}).(rawMD)
  161. added := make([][]string, len(md.added)+1)
  162. copy(added, md.added)
  163. kvCopy := make([]string, 0, len(kv))
  164. for i := 0; i < len(kv); i += 2 {
  165. kvCopy = append(kvCopy, strings.ToLower(kv[i]), kv[i+1])
  166. }
  167. added[len(added)-1] = kvCopy
  168. return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md.md, added: added})
  169. }
  170. // FromIncomingContext returns the incoming metadata in ctx if it exists.
  171. //
  172. // All keys in the returned MD are lowercase.
  173. func FromIncomingContext(ctx context.Context) (MD, bool) {
  174. md, ok := ctx.Value(mdIncomingKey{}).(MD)
  175. if !ok {
  176. return nil, false
  177. }
  178. out := make(MD, len(md))
  179. for k, v := range md {
  180. // We need to manually convert all keys to lower case, because MD is a
  181. // map, and there's no guarantee that the MD attached to the context is
  182. // created using our helper functions.
  183. key := strings.ToLower(k)
  184. out[key] = copyOf(v)
  185. }
  186. return out, true
  187. }
  188. // ValueFromIncomingContext returns the metadata value corresponding to the metadata
  189. // key from the incoming metadata if it exists. Keys are matched in a case insensitive
  190. // manner.
  191. //
  192. // # Experimental
  193. //
  194. // Notice: This API is EXPERIMENTAL and may be changed or removed in a
  195. // later release.
  196. func ValueFromIncomingContext(ctx context.Context, key string) []string {
  197. md, ok := ctx.Value(mdIncomingKey{}).(MD)
  198. if !ok {
  199. return nil
  200. }
  201. if v, ok := md[key]; ok {
  202. return copyOf(v)
  203. }
  204. for k, v := range md {
  205. // Case insenitive comparison: MD is a map, and there's no guarantee
  206. // that the MD attached to the context is created using our helper
  207. // functions.
  208. if strings.EqualFold(k, key) {
  209. return copyOf(v)
  210. }
  211. }
  212. return nil
  213. }
  214. func copyOf(v []string) []string {
  215. vals := make([]string, len(v))
  216. copy(vals, v)
  217. return vals
  218. }
  219. // FromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD.
  220. //
  221. // Remember to perform strings.ToLower on the keys, for both the returned MD (MD
  222. // is a map, there's no guarantee it's created using our helper functions) and
  223. // the extra kv pairs (AppendToOutgoingContext doesn't turn them into
  224. // lowercase).
  225. //
  226. // This is intended for gRPC-internal use ONLY. Users should use
  227. // FromOutgoingContext instead.
  228. func FromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) {
  229. raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
  230. if !ok {
  231. return nil, nil, false
  232. }
  233. return raw.md, raw.added, true
  234. }
  235. // FromOutgoingContext returns the outgoing metadata in ctx if it exists.
  236. //
  237. // All keys in the returned MD are lowercase.
  238. func FromOutgoingContext(ctx context.Context) (MD, bool) {
  239. raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
  240. if !ok {
  241. return nil, false
  242. }
  243. mdSize := len(raw.md)
  244. for i := range raw.added {
  245. mdSize += len(raw.added[i]) / 2
  246. }
  247. out := make(MD, mdSize)
  248. for k, v := range raw.md {
  249. // We need to manually convert all keys to lower case, because MD is a
  250. // map, and there's no guarantee that the MD attached to the context is
  251. // created using our helper functions.
  252. key := strings.ToLower(k)
  253. out[key] = copyOf(v)
  254. }
  255. for _, added := range raw.added {
  256. if len(added)%2 == 1 {
  257. panic(fmt.Sprintf("metadata: FromOutgoingContext got an odd number of input pairs for metadata: %d", len(added)))
  258. }
  259. for i := 0; i < len(added); i += 2 {
  260. key := strings.ToLower(added[i])
  261. out[key] = append(out[key], added[i+1])
  262. }
  263. }
  264. return out, ok
  265. }
  266. type rawMD struct {
  267. md MD
  268. added [][]string
  269. }